platform-ui-home/components-proposal/ComponentFrameworkProposal.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (download) (as text) (annotate)
Sat Nov 6 00:49:47 2004 UTC (5 years ago) by sxenos
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +992 -184 lines
Version 1.0.4 - more content, new introduction, renamed "services" to "interfaces"
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1"
 http-equiv="content-type">
  <title>Component Framework proposal</title>
</head>
<body>
<span style="font-weight: bold;"></span>
<br>
<div style="text-align: center;"><font size="+3"><span
 style="font-weight: bold;">Component Framework Proposal</span></font><br>
</div>
<br>
<div style="text-align: center;">Draft<br>
Revision 1.0.4<br>
By Stefan Xenos and Nick Edgar<br>
Last modified 2004/11/05<br>
</div>
<br>
<br>
<br>
<font size="+3"><span style="font-weight: bold;">Table of Contents</span></font><br>
<ul id="mozToc">
<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId511305">1.0
Introduction
    </a>
    <ul>
      <li><a href="#mozTocId619855">1.1 Understanding the problem</a></li>
      <li><a href="#mozTocId340323">1.2 Requirements
        </a>
        <ul>
          <li><a href="#mozTocId29093">1.2.1 Robustness /
leak
proofing
            </a></li>
          <li><a href="#mozTocId223982">1.2.2 Nesting of
components</a></li>
          <li><a href="#mozTocId634024">1.2.3 Creating parts
outside the workbench</a></li>
          <li><a href="#mozTocId800379">1.2.4 Scalability</a></li>
          <li><a href="#mozTocId866479">1.2.5 Ease of use
            </a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#mozTocId416167">2.0 Component
Framework
    </a>
    <ul>
      <li><a href="#mozTocId489102">2.1 Instantiating a
view
        </a></li>
      <li><a href="#mozTocId717633">2.2 Instantiating
components in general
        </a></li>
      <li><a href="#mozTocId450231">2.3 Creating
dependent components on demand </a></li>
      <li><a href="#mozTocId928619">2.4 Declaring Component Interfaces</a></li>
      <li><a href="#mozTocId749133">2.5 Using Component Interfaces</a></li>
      <li><a href="#mozTocId705695">2.6 Lifecycle</a></li>
      <li><a href="#mozTocId543223">2.7 Dynamic Interfaces</a></li>
      <li><a href="#mozTocId886834">2.8 Optional Interface
        </a></li>
      <li><a href="#mozTocId578639">2.8 Component Scopes</a></li>
      <li><a href="#mozTocId762751">2.9 Shared Adapters</a></li>
    </ul>
  </li>
  <li><a href="#mozTocId707022">3.0 Views and Editors
as Components</a>
    <ul>
      <li><a href="#mozTocId125361">3.1 Interfaces offered by the
workbench</a>
        <ul>
          <li><a href="#mozTocId163729">3.1.1 IMultiPart: Redirecting
adapters from the active child
            </a></li>
          <li><a href="#mozTocId483376">3.1.2 INameable: Changing the
name of a part</a></li>
          <li><a href="#mozTocId969580">3.1.3 IPartFactory: Creating
child parts</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
<br>
<h1><a class="mozTocH1" name="mozTocId511305"></a>1.0 Introduction<br>
</h1>
This proposal outlines a framework for managing complex executable
extensions. This framework is a first step toward allowing views and
editors to be combined recursively, and created inside arbitrary SWT
composites. Although it is intended for creating reusable UI
components, the framework is useful for any extension point that
creates complicated Java objects. For this reason, we will refer to the
objects being created as "components" even though our components are
typically views and editors.<br>
<br>
This proposal is broken into three parts. The introduction describes
the motivation for creating the component framework and its
requirements. The second section describes the component framework in
itself, which could be used for any executable extension point. The
third section describes how the workbench will use the component
framework for views and editors.<br>
<br>
<h2><a class="mozTocH2" name="mozTocId619855"></a>1.1 Understanding the
problem</h2>
This section explains why the component framework is needed to support
nested parts. We will show the problems involved in designing an
extensible Site interface, and will show how they can be solved using
the patterns in the component framework. Skip to the next sections if
you don't need convincing and just want to see the specification.
IMPORTANT NOTE:
the code examples in this section are only intended to illustrate
patterns and do not reflect the actual implementation<br>
<br>
Currently, parts communicate with their parent through their site. The
site provides the view with access to the outside world. In general, it
is better to provide new API on the part's site than have the part
reach to some global object, since the site can provide some context
and can manage resources allocated to the part.<br>
<br>
Here is a simplified version of the View and Site interface. We've
omitted most of the details. The important part is that the View is
given a Site when it is initialized, it uses various methods on the
Site throughout its life, and the Site has a dispose() method that can
clean up after the View.<br>
<code><br>
</code>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* A view's main interface to the world.<br>
&nbsp;*/<br>
public class Site {<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Create a view site, given the plugin that
contains the implementation for the view<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public Site(Plugin viewPlugin) {<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Return the view's ID<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public String getId() {...};<br>
<br>
&nbsp;&nbsp;&nbsp; public IActionBars getActionBars() {...};<br>
<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Clean up any leftover resources allocated by
the site<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public void dispose() {<br>
&nbsp;&nbsp;&nbsp; };<br>
}<br>
<br>
/**<br>
&nbsp;* Base class for all views.<br>
&nbsp;*/<br>
public abstract class View {<br>
&nbsp;&nbsp;&nbsp; private Site mySite;<br>
<br>
&nbsp;&nbsp;&nbsp; public View(Site viewSite) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; mySite = viewSite;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public Site getSite() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return mySite;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public abstract String getTitle();<br>
<br>
&nbsp;&nbsp;&nbsp; public void dispose() {};<br>
}<br>
<br>
/**<br>
&nbsp;* A factory that can create views by ID.<br>
&nbsp;*/<br>
public ViewFactory {<br>
&nbsp;&nbsp;&nbsp; public static View createView(String
viewExtensionId, Site viewSite) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //... create a view and return it<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
</code></div>
<br>
Anyone that wants to instantiate a view would need to create an
instance of Site and create the view by calling ViewFactory.createView.
It would be possible to subclass Site in order to provide the part with
additional context. For example, a subclass of Site could overload
getActionBars() to substitute a different implementation of IActionBars
to be used by the view. <br>
<br>
One of the problems with using the Site as the main interface to a view
is that we continually need to add new methods to the Site base class.
For example, we might decide to add a logError method that allows views
to log exceptions to their plugin log without needing to reach to their
Plugin object or worry about constructing IStatus instances with the
correct plugin ID.<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* A view's main interface to the world.</code><br>
<code>&nbsp;*/</code><br>
<code>public class Site {<br>
&nbsp;&nbsp;&nbsp; Plugin plugin;<br>
<br>
</code><code></code><code>&nbsp;&nbsp;&nbsp; public Site(Plugin
viewPlugin) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; plugin = viewPlugin;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; // ...all other Site methods omitted...<br>
<br>
</code><code>&nbsp;&nbsp;&nbsp; public void logError(Throwable t) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; plugin.getLog().log(new Status(..., t));<br>
&nbsp;&nbsp;&nbsp; };<br>
</code><code>}</code><br>
</div>
<br>
The site could also provide the view with localized ways to allocate
resources. For example, if the view could allocate Images through its
site, the Site could guarantee that the images would be cleaned up
properly when the view is destroyed.<br>
<div style="margin-left: 40px;"><code><br>
/**</code><br>
<code>
&nbsp;* A view's main interface to the world.</code><br>
<code>
&nbsp;*/</code><br>
<code>
public class Site {<br>
<br>
&nbsp;&nbsp;&nbsp; // .... everything in the above version of Site plus
this:<br>
<br>
&nbsp;&nbsp;&nbsp; Map allocatedImages = new HashMap();<br>
<br>
&nbsp;&nbsp;&nbsp; public Image createImage(ImageDescriptor toCreate) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Image image =
toCreate.createImage(true);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; allocatedImages.put(toCreate, image);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return image;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public void destroyImage(ImageDescriptor toDestroy) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Image image =
allocatedImages.get(toDestroy);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (image != null) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
allocatedImages.remove(toDestroy);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; image.dispose();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public void dispose() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Collection values =
allocatedImages.getValueSet();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Iterator iter = values.iterator();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; while (iter.hasNext()) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; Image img =
(Image)iter.next();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; img.dispose();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }</code><code><br>
</code><code>
}<br>
<br>
</code></div>
In order to provide the best protection against leaks, new API should
use this pattern as much as possible for views. The obvious problems
with this are:<br>
<ol>
  <li>Whoever implements the Site class can't possibly know about every
type of resource that might be allocated by every view</li>
  <li>The Site interface would become ridiculously large and
complicated.<br>
  </li>
</ol>
It would be possible to work around this by writing new subclasses of
Site that add new methods, but then Views that use the new APIs would
not function properly when given a different Site implementation. The
ideal solution would allow plugins to contribute new default behavior
to the Site base class, and only require the Site class to be
subclassed when this behavior needs to be specialized. This can be
achieved by making Site adaptable. Rather than always adding new
methods to Site, plugins couldcontribute adapters. Subclasses of site
would still be able to override the default adapter behavior by
explicitly implementing the adapter interface, but parts that use the
adapter would no longer be tied to a particular Site implementation.<br>
<br>
Here is an example that demonstrates the pattern:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>
&nbsp;* Adapter for a view site that allows allocation/deallocation of
images</code><br>
<code>
&nbsp;*/</code><br>
<code>
public interface IImageAllocator {<br>
&nbsp;&nbsp;&nbsp; public Image createImage(ImageDescriptor toCreate);<br>
&nbsp;&nbsp;&nbsp; public void destroyImage(ImageDescriptor toDestroy);<br>
</code><code>}<br>
<br>
/**<br>
&nbsp;* Implementation of the image allocator adapter provided via XML<br>
&nbsp;* by some plugin.<br>
&nbsp;*/<br>
public class ImageAllocator implements IImageAllocator, IDisposable {<br>
&nbsp;&nbsp;&nbsp; </code><code>public Image
createImage(ImageDescriptor toCreate) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; };<br>
<br>
&nbsp;&nbsp;&nbsp; public void destroyImage(ImageDescriptor toDestroy) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; };<br>
<br>
&nbsp;&nbsp;&nbsp; public void dispose() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // Dispose any images leaked through
createImage<br>
&nbsp;&nbsp;&nbsp; };<br>
</code><code>}<br>
<br>
/**<br>
&nbsp;* Next attempt at a site interface<br>
&nbsp;*/<br>
public class Site implements IAdaptable {<br>
<br>
&nbsp;&nbsp;&nbsp; List disposableAdapters = new ArrayList();<br>
<br>
&nbsp;&nbsp;&nbsp; public Object getAdapter(Class adapterType) {<br>
</code><code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Object result = //</code><code>...some
magic that looks through the adapter extension point and<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //creates an instance of ImageAllocator<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (adapter instanceof IDisposable) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
disposableAdapters.add(adapter);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return result;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Allow all the adapters to clean up anything
they allocated.<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public void dispose() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Iterator iter =
disposableAdapters.iterator();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; while(iter.hasNext()) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; IDisposable next =
(IDisposable)iter.next();<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; next.dispose();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
</code><code>/**<br>
&nbsp;* Base class for all views.<br>
&nbsp;*/<br>
public abstract class View {<br>
&nbsp;&nbsp;&nbsp; private IAdaptable mySite;<br>
<br>
&nbsp;&nbsp;&nbsp; public View(IAdaptable viewSite) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; mySite = viewSite;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public IAdaptable getSite() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return mySite;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public abstract String getTitle();<br>
<br>
&nbsp;&nbsp;&nbsp; public void dispose() {};<br>
}</code><br>
</div>
<br>
Notice that this type of adapter is slightly different from most other
adapters in Eclipse since it keeps some state and need to be notified
when the Site is disposed. <br>
<br>
A particular view would look like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* My implementation of a view<br>
&nbsp;*/<br>
public class MyView extends View {<br>
&nbsp;&nbsp;&nbsp; IImageAllocator allocator;<br>
<br>
&nbsp;&nbsp;&nbsp; public MyView(IAdaptable viewSite) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; allocator =
(IImageAllocator)viewSite.getAdapter(IImageAllocator.class);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (allocator == null) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; throw new Exception("I
can't exist without images!");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; //...<br>
}<br>
<br>
</code></div>
Most views will contain similar code in their constructor that requests
a set of adapters from their site and check that they aren't null. We
can add some syntactic sugar to remove this repetition. Rather than
having the view explicitly request every adapter it needs, it can take
them as arguments to its constructor and the factory that creates the
view can use reflection to ensure that it gets all the adapters it
needs. Using this pattern, the same view would look like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* My implementation of a view</code><br>
<code>&nbsp;*/</code><br>
<code>public class MyView extends View {</code><br>
<code>&nbsp;&nbsp;&nbsp; IImageAllocator allocator;</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public MyView(IImageAllocator imageAllocator) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; allocator = imageAllocator;<br>
</code><code></code><code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; //...</code><br>
<code>}<br>
<br>
</code></div>
Since the entire Site API would be provided by adapters, the Site class
could be reduced to this:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* My implementation of a view</code><br>
<code>&nbsp;*/</code><br>
<code>public abstract class Site implements IAdaptable {<br>
&nbsp;&nbsp;&nbsp; public abstract Object getAdapter(Class adapter);<br>
&nbsp;&nbsp;&nbsp; public abstract void dispose();<br>
</code><code></code><code>}</code><br>
</div>
<br>
In the component framework, this simplified Site interface is called
IContainer. We now have a highly extensible Site interface, however the
same versioning problems apply to the view as well. The parent of the
view may want to access methods on the View, but we don't want to be
continually adding things to the View base class. For this reason, we
communicate with the view through adapters as well.<br>
<br>
This is the core pattern behind the component framework. It consists of:<br>
<ol>
  <li>An extension point that allows 3rd party plugins to contribute
interfaces to components (views and their sites)<br>
  </li>
  <li>A factory that allows components to be created through
constructor injection</li>
  <li>A container interface that manages the lifecycle of components
and their adapters </li>
</ol>
<div style="margin-left: 40px;"></div>
<h2><a class="mozTocH2" name="mozTocId340323"></a>1.2 Requirements<br>
</h2>
Primary goals:<br>
<ul>
  <li>Robustness / leak proofing</li>
  <li>Nesting of components</li>
  <li>Allow components to be reused outside the workbench</li>
  <li>Scalability (allow an open-ended set of components)</li>
  <li>API versioning<br>
  </li>
  <li>Ease of use</li>
</ul>
<h3><a class="mozTocH2" name="mozTocId29093"></a>1.2.1 Robustness /
leak
proofing<br>
</h3>
Much of the Eclipse API is currently accessed through singleton
objects. This makes it easy for a view or editor to leak listeners,
fail to clean up reference counts, leak OS resources, etc. since there
is no way of tracking which resources were allocated by a particular
view. This problem would be reduced if views and editors were more like
mini-applications. The view or editor would access the rest of the
world through a set of local interfaces. When the view or editor is
destroyed, all the interfaces would be notified giving them a chance to
clean up any leaked resources.<br>
<br>
For example, instead of reaching into a global
preference store, a view or editor could access all preferences through
a local preference adapter. A unique instance of the local preference
adapter would be
created for each view, and would be disposed with the view. When the
preference adapter is destroyed it would clear its listener list,
ensuring that the view will not leak any global listeners. This example
shows what we mean by a component. Essentially, a
component is an object that communicates with the rest of the
application through a set of interfaces given to it in its constructor.<br>
<span style="font-weight: bold;"></span>
<h3><a class="mozTocH2" name="mozTocId223982"></a>1.2.2 Nesting of
components</h3>
There is demand for the ability to embed views and editors inside one
another. Some examples:<br>
<ul>
  <li>An XML editor might embed the properties view</li>
  <li>A refactoring wizard might include a source editor</li>
  <li>A plugin may wish to create a set of pluggable UI components that
are not views or editors themselves, but can be used inside any view or
editor</li>
  <li>Various workbench objects (like the PartSashContainer that
handles the layout of docked parts within the workbench) could be
exposed as API<br>
  </li>
</ul>
Many downstream plugins have solved these problems by creating their
own frameworks for reusable UI components. Unfortunately, this only
works
for specific views and editors, does not encourage interoperability
between plugins that have adopted different frameworks, and requires a
lot of work. The goal here is to adopt a framework in the workbench
itself that allows all editors, views, and other workbench objects to
be easily nested.<br>
<h3><a class="mozTocH2" name="mozTocId634024"></a>1.2.3 Creating parts
outside the workbench</h3>
It should be possible to instantiate views and editors outside the
workbench. Some examples:<br>
<ul>
  <li>Unit-test editors and views by instantiating them within a JUnit
test suite.</li>
  <li>Create an RCP application that does not depend on the workbench
but includes view-like pluggable parts
that could also be used as views within Eclipse</li>
</ul>
<h3><a class="mozTocH2" name="mozTocId800379"></a>1.2.4 Scalability</h3>
The workbench currently offers a closed interface to parts. This
forces parts to reach to global objects whenever they need something
that isn't available from their site. It should be possible for any
plugin to contribute to the set of local API available to a part, and
it
should be possible to instantiate a part even if its parent doesn't
know about all of a part's dependencies.<br>
<h3><a class="mozTocH2" name="mozTocId866479"></a>1.2.5 Ease of use<br>
</h3>
Views and editors currently have a complicated lifecycle that must be
managed by the workbench. This complexity should not be exposed to
client code. <br>
<ul>
  <li>It should only require one method call to create a component and
one method call to destroy it.</li>
  <li>There should not be unnecessary duplication between XML and java
code.</li>
  <li>Components should not
be responsible for dealing with error conditions (such as missing
dependencies) that can be detected by the framework.</li>
  <li>Components should not need to implement interfaces they don't
care about.</li>
  <li>A parent context should not need to provide child components with
interfaces it doesn't care about.<span style="font-weight: bold;"></span></li>
</ul>
<h1><a class="mozTocH1" name="mozTocId416167"></a>2.0 Component
Framework<br>
</h1>
First, some terminology. The pluggable objects that clients write are
called "components". For example, the class that contains the
implementation of a view itself would be called a component. A
component exists inside an IContainer. In the case of editors and
views, IContainer replaces the existing IWorkbenchSite. Unlike
IWorkbenchSite, the component never needs to directly access the
IContainer since all of its useful interface is provided through
adapters. Instead, the component supplies a constructor that takes all
the interfaces it needs, and it communicates with the outside world
through these interfaces.<br>
<br>
Components are built using constructor
injection. Constructor injection means that the framework looks at the
object's constructor to determine what it needs to do to build that
object.<br>
<br>
Components:<br>
<ul>
  <li>Have exactly one constructor</li>
  <li>Take zero or more other components as arguments to their
constructor</li>
  <li>Are fully initialized by their constructor</li>
</ul>
Components do not:<br>
<ul>
  <li>Take arrays or primitives as arguments to their constructor</li>
  <li>Take more than one argument of the same type in their constructor<br>
  </li>
  <li>Need to support any particular base class or interface</li>
</ul>
Any class with these properties can be used as a component. Since
components are plain-old-java-objects, they do not need to depend on
the component framework. Components are fully initialized by
their constructor, meaning it is never necessary
to call an initialize method or any combination of set methods after
constructing the object. Components never accept null as an argument
to their constructor.<br>
<br>
For example, if a view could be created as a component it might look
like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* "Hello world" view using the component framework</code><br>
<code>&nbsp;*/</code><br>
<code>public class HelloWorldView {</code><br>
<code>&nbsp;&nbsp;&nbsp; public HelloWorldView(Composite parent) {</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Label helloWorld = new
Label(parent, SWT.NONE);</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
helloWorld.setText("Hello
world");</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code></div>
<code><br>
</code>The HelloWorldView component depends on one other object: a
Composite
created for it by whoever instantiated the view. Compare this with the
same view written using the existing API:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* "hello world" view using the Eclipse 3.0 API.</code><br>
<code>&nbsp;*/</code><br>
<code>public class HelloWorldView extends ViewPart {</code><br>
<code>&nbsp;&nbsp;&nbsp; public void createPartControl(Composite
parent) {</code><br>
<code></code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Label
helloWorld = new Label(parent, SWT.NONE);</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
helloWorld.setText("Hello
world");</code><code>&nbsp;&nbsp; </code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void setFocus() {</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
</div>
<br>
The main difference is that the component version does not require the
ViewPart base class and is fully initialized after construction. In
both cases, the extension point markup would look like this:<br>
<br>
<div style="margin-left: 40px;"><code>&lt;extension
point="org.eclipse.ui.views"&gt;</code><br>
<code>&nbsp;&nbsp;&nbsp; &lt;view</code><br>
<code>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; name="Title Test View"</code><br>
<code>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; icon="icons\view.gif"</code><br>
<code>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
class="org.eclipse.ui.mytest.HelloWorldView"</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; id="</code><code>org.eclipse.ui.mytest.HelloWorldView</code><code>ID"&gt;</code><br>
<code>&nbsp;&nbsp;&nbsp; &lt;/view&gt;</code><br>
<code>&lt;/extension&gt;</code><br>
</div>
<br>
<h2><a class="mozTocH2" name="mozTocId489102"></a>2.1 Instantiating a
view<br>
</h2>
Components are instantiated using factories. For the moment, let's
focus on views before we explore components in general. Views could be
created using a method on IWorkbenchPage that would look something like
this. Note that this example is only intended to illustrate the general
idea -- the actual protocol for creating views is likely to change.<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* Creates a view of the given type inside the given
composite.
The caller must dispose the container once they are done with it.</code><br>
<code>&nbsp;*</code><br>
<code>&nbsp;* @param viewId id of the view extension to use</code><br>
<code>&nbsp;* @param parentComposite parent composite for the view</code><br>
<code>&nbsp;* @return an IContainer that contains all components needed
for the view</code><br>
<code>&nbsp;*/</code><br>
<code>IContainer createView(String viewId, Composite parentComposite);</code><br>
<code></code></div>
<code></code><br>
<br>
This creates a new instance of the view in the given composite. Notice
that the factory method doesn't return an instance of the view itself
but an instance of IContainer, which looks something like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* Main interface to a component.</code><br>
<code>&nbsp;*/</code><br>
<code>public interface IContainer extends IAdaptable {</code><br>
<code></code>&nbsp; &nbsp;&nbsp; public void dispose();<br>
}<br>
</div>
<br>
This interface wraps the component and all of its dependencies. Once
we've obtained an IContainer handle, we are obligated to dispose it
when we are done with it. All access to the component is done through
adapters, which insulates
the application from changes in individual views. For example, if a
view that previously implemented the IViewInterface1 migrates to using
the newer IViewInterface2, its container will continue to work as long
as someone has provided an adapter between the two versions of
IViewInterface. The getAdapter() method on IContainer searches for
adapters in the following order:<br>
<br>
1. If the component itself implements the adapter type, it returns the
component.<br>
2. If the component itself implements IAdapter, and the component's
getAdapter(...) method returns non-null, we return that adapter.<br>
3. If the adapter manager has an adapter between the component and the
adapter type, we return that adapter.<br>
4. If the container's factory can construct a component of the
requested type, we
create that component, add it as a local dependency to the IContainer,
and
return it.<br>
5. Return null<br>
<br>
For example, it would be possible to create our HelloWorldView (above)
in a modal dialog like this:<br>
<br>
<div style="margin-left: 40px;"><code>void
createHelloWorldViewInADialog(IWorkbenchPage page) {</code><br>
<code>&nbsp;&nbsp;&nbsp; Display display = Display.getDefault()</code><br>
<code>&nbsp;&nbsp;&nbsp; Shell shell = new Shell(Display.getDefault());</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; shell.setLayout(new FillLayout());</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; // Create the view and its widgets</code><br>
<code>&nbsp;&nbsp;&nbsp; IContainer myView =
workbenchPage.createView("org.eclipse.ui.mytest.HelloWorldViewID",
shell);</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; shell.open();</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; while (!shell.isDisposed()) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (!display.readAndDispatch ())
display.sleep ();</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; // Dispose the view</code><br>
<code>&nbsp;&nbsp;&nbsp; myView.dispose();</code><br>
<code>}</code><br>
<code></code></div>
<h2><a class="mozTocH2" name="mozTocId717633"></a>2.2 Instantiating
components in general<br>
</h2>
All components are constructed using an IContainerFactory, however most
component-based extension points will provide some
sort of convenience method to wrap their IContainerFactory. The
IWorkbenchPage.createView method in the
previous section is a convenience method for the <span
 style="font-style: italic;">org.eclipse.ui.views </span>extension
point.<br style="font-style: italic;">
&nbsp;<br>
IContainerFactory looks like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* Factory for IContainer instances. The default factory is
returned by<br>
&nbsp;* Components.getFactory(). Clients wishing to implement their own
specialized <br>
&nbsp;* factories should call createDerivedFactory() to get access to a
factory<br>
&nbsp;* whose behavior can be modified programmatically. Not intended
to be <br>
&nbsp;* implemented by clients. <br>
&nbsp;* <br>
&nbsp;* @since 3.1<br>
&nbsp;*/<br>
public interface IContainerFactory {<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Creates and returns a new IContainer
instance, given the <br>
&nbsp;&nbsp;&nbsp;&nbsp; * implementation class for its component. The
caller MUST call IContainer.dispose() <br>
&nbsp;&nbsp;&nbsp;&nbsp; * when it is done with the component. The
factory does not need any prior<br>
&nbsp;&nbsp;&nbsp;&nbsp; * knowledge of the component class.<br>
&nbsp;&nbsp;&nbsp;&nbsp; * <br>
&nbsp;&nbsp;&nbsp;&nbsp; * @param componentImplementation concrete
class to be instantiated by the factory. The class<br>
&nbsp;&nbsp;&nbsp;&nbsp; * &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
must be a valid component (it must have exactly one constructor which
only<br>
&nbsp;&nbsp;&nbsp;&nbsp; * &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
references other component interfaces known to this factory).<br>
&nbsp;&nbsp;&nbsp;&nbsp; * @return a newly constructed
&lt;code&gt;IContainer&lt;/code&gt; instance<br>
&nbsp;&nbsp;&nbsp;&nbsp; * @throws CoreException if unable to create
the component<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public IContainer createContainer(Class
componentImplementation) throws CoreException;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Creates a specialization of this factory. By
default, the specialized<br>
&nbsp;&nbsp;&nbsp;&nbsp; * factory will have the same behavior as its
parent. However, the derived<br>
&nbsp;&nbsp;&nbsp;&nbsp; * factory can add, or override the
implementation for any components.<br>
&nbsp;&nbsp;&nbsp;&nbsp; * <br>
&nbsp;&nbsp;&nbsp;&nbsp; * @return new factory instance that allows
individual components to be overridden.<br>
&nbsp;&nbsp;&nbsp;&nbsp; * By default, the derived factory will
delegate all of its behavior to the receiver.<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Changes in the receiver will affect the
derived factory.<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public IMutableContainerFactory
createDerivedFactory();<br>
}</code><code></code><br>
<code></code></div>
<code></code><br>
All arguments to a component's constructor are provided by its factory.
Different
factories know how to create different types of components or will
provide
different implementations for the same components. All factories are
derived from the root factory, which is returned by
Components.getFactory(). A plugin can create derived factories to
supply alternative adapter implementations to the components it creates.<br>
<br>
In
our case, we will create a container factory to pass a specific
Composite into the constructor of HelloWorldView. The code looks like
this:<br>
<code></code><code><br>
</code>
<div style="margin-left: 40px;"><code>// Get the global factory</code><br>
<code>IContainerFactory viewFactory =
Components.getFactory();</code><br>
<code></code><br>
<code>// Create the Composite for the view</code><br>
<code></code><code>Composite viewComposite = new
Composite(parentComposite, SWT.NONE);</code><br>
<code>viewComposite.setLayout(new FillLayout();</code><br>
<code></code><br>
<code>// Create a specialized factory that knows about the view's
composite and plugin bundle</code><br>
<code>IMutableContainerFactory derivedFactory =
viewFactory.createDerivedFactory();</code><br>
<code></code><br>
<code>// Add the view's composite to the factory so that it can be seen
by the view constructor<br>
</code><code>derivedFactory.addComponentInstance(viewComposite);</code><br>
<code></code><br>
<code>// Add the view's plugin bundle to the factory (not
required in this example, but this</code><br>
<code>// is recommended practise for any component created from an
extension point).</code><br>
<code>derivedFactory.addComponentInstance(pluginBundle);</code><br>
<code></code><br>
<code>// Create the view. Provide its constructor and some
context (the page that created it).</code><br>
<code>IContainer view =
derivedFactory.createContainer(HelloWorldView.class);</code><br>
<code></code><br>
<code>// Do something with the view</code><br>
<code>// ...</code><br>
<code></code><br>
<code>// Now clean up</code><br>
<code>view.dispose();</code><br>
<code>viewComposite.dispose();</code><br>
<code></code></div>
<code><br>
</code><br>
This code will work, but it has two problems:<br>
<br>
1. Even if HelloWorldView didn't require a Composite, we would still
have created one (which is wasteful).<br>
2. We need to manually dispose the view's composite after we're done
with it. This defeats the point of IContainer.dispose(), which is
supposed to clean up all of the component's dependencies automatically.<br>
<h2><a class="mozTocH2" name="mozTocId450231"></a>2.3 Creating
dependent components on demand </h2>
Rather than managing the view's Composite ourselves, we could supply a
factory that knows how to create and destroy Composites as needed. Such
a factory would look like this:<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* ComponentAdapter for creating and managing SWT Composites.</code><br>
<code>&nbsp;*/</code><br>
<code>public class CompositeFactory extends ComponentAdapter {</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; private Composite parent;</code><br>
<code>&nbsp;&nbsp;&nbsp; </code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * The SWT composites created by this
factory will all be children of the given</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * composite.</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public CompositeFactory(Composite parent) {</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.parent = parent;</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; </code><br>
<code>&nbsp;&nbsp;&nbsp; protected Object create(IAdaptable
availableAdapters) throws CoreException {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // Create a new Composite</code><code></code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Composite newChild =
new Composite(parent, SWT.NONE);</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newChild.setLayout(new
FillLayout());</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return newChild;</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; protected void dispose(Object toDispose) {</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
((Composite)toDispose).dispose();</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public String getInterfaceName() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // Return the fully
qualified class name of the Composite class. The framework will call</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // this method to determine
what type of interface will be implemented by the objects <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // constructed by this factory.</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return
Composite.class.getName();</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code></div>
<br>
Using CompositeFactory, we could construct HelloWorldView like this:<br>
<br>
<div style="margin-left: 40px;"><code>// Get the global factory</code><br>
<code>IContainerFactory viewFactory =
Components.getFactory();</code><code></code><br>
<code></code><br>
<code>// Create a specialized factory that knows about the view's
composite and plugin bundle</code><br>
<code>IMutableContainerFactory derivedFactory =
viewFactory.createDerivedFactory();</code><br>
<code></code><br>
<code>// Add a factory that can create the view's composite</code><br>
<code>derivedFactory.addComponentFactory(new
CompositeFactory(parentComposite));</code><br>
<code></code><br>
<code>// Add the view's plugin bundle to the factory (not
required in this example, but this</code><br>
<code>// is recommended practise for any component created from an
extension point).</code><br>
<code>derivedFactory.addComponentInstance(pluginBundle);</code><br>
<code></code><br>
<code>// Create the view. Provide its constructor and some
context (the page that created it).</code><br>
<code>IContainer view =
derivedFactory.createComponent(HelloWorldView.class);</code><br>
<code></code><br>
<code>// Do something with the view</code><br>
<code>// ...</code><br>
<code></code><br>
<code>// Now clean up</code><br>
<code>view.dispose();</code><br>
<code></code></div>
<code>
</code><br>
The composite will now be allocated as needed and disposed inside the
call to view.dispose().<br>
<br>
<code></code>
<h2><a class="mozTocH2" name="mozTocId928619"></a>2.4 Declaring
Component Interfaces</h2>
The types that a component receives in its constructor are called
component interfaces. Component interfaces are registered through the <span
 style="font-style: italic;">org.eclipse.core.component.interface</span>
extension point, and each has a default implementation. When a
component is
created, its parent may provide an implementation of any service
it knows about. If the component requests an interface that isn't
provided explicitly by the parent, the default implementation is used.<br>
<br>
Here is an
example component interface:<br>
<code><br>
</code>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* Component interface: </code><br>
<code>&nbsp;*</code><br>
<code>&nbsp;* Provides a context for reporting and logging exceptions.</code><br>
<code>&nbsp;*/</code><br>
<code>public interface IErrorContext {</code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * Create an IStatus error describing the
given
throwable</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public IStatus createStatus(Throwable t);</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * Create an IStatus message with the
given
severity, message, and (optional) throwable</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public IStatus createStatus(int severity,
String
message, Throwable t);</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * Logs an IStatus message</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public void log(IStatus status);</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp; &nbsp;&nbsp; * Logs an exception to the system log</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public void log(Throwable t);</code><br>
<code>}</code><br>
<code></code></div>
<code><br>
<br>
</code>Here is the associated default implementation:<br>
<code><br>
</code>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* Default implementation of the IErrorContext interface:</code><br>
<code>&nbsp;*</code><br>
<code>&nbsp;* Creates and logs errors in the context of a plugin bundle</code><br>
<code>&nbsp;*/</code><br>
<code>public class ErrorContext implements IErrorContext {</code><br>
<code>&nbsp;&nbsp;&nbsp; private Bundle pluginBundle;</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public ErrorContext(Bundle
pluginBundle) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; this.pluginBundle =
pluginBundle;</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public IStatus createStatus(Throwable t) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; String message = t.getMessage();</code><br>
<code>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (message == null) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; message =
t.getString();</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return createStatus(Status.ERROR,
message, t);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public IStatus createStatus(int severity,
String
message, Throwable t) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return new Status(severity,
pluginBundle.getSymbolicName(), Status.OK, message, t);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void log(Throwable t) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; log(createStatus(t));</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void log(IStatus status) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Plugin plugin =
Platform.getPlugin(pluginBundle.getSymbolicName());</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; plugin.getLog().log(status);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code></div>
<code></code><br>
Finally, here is the extension markup:<br>
<br>
<div style="margin-left: 40px;"><code>&lt;extension
point="org.eclipse.core.component.interface"&gt;</code><br>
<code>&nbsp;&nbsp; &lt;interface
</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;
class="org.eclipse.ui.workbench.ErrorContext"</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; </code><code>interface="</code><code>org.eclipse.ui.workbench.IErrorContext</code><code>"<br>
&nbsp;&nbsp;&nbsp;&nbsp; childadapter="false"<br>
</code><code>&nbsp;&nbsp;&nbsp;&nbsp; scope="plugin"&gt;</code><br>
<code>&nbsp;&nbsp; &lt;/interface&gt;</code><br>
<code>&lt;/extension&gt;</code><br>
</div>
<br>
Notice that the extension XML needs to indicate which service interface
is being implemented by the service, but not its dependencies. When it
comes time to create the service, the framework detects that the
ErrorContext needs to be associated with a plugin Bundle by examining
its constructor. This means that if plugin A defines the ErrorContext
service and plugin B defines a view that uses the service, then all of
the status messages constructed by the view will be associated with the
view's own plugin - not the plugin that defined the ErrorContext
service.<br>
<br>
The <span style="font-style: italic;">scope</span> attribute is a path
indicating how much context is needed to create the service. The <span
 style="font-style: italic;">plugin </span>scope indicates that this
service is associated with a plugin, which is why it is allowed to take
a Bundle in its constructor. More on scopes later.<br>
<br>
The <span style="font-style: italic;">childadapter="false" </span>tag
is optional. The default value, false, indicates that a component can
take the interface in its constructor and/or supply an alternative
implementation to its children. If <span style="font-style: italic;">childadapter="true"</span>
were specified, the component would be allowed to implement the
interface or request it from its children. Essentially, this determines
if the interface is intended for top-down or bottom-up communication
between a component and its parent.<br>
<br>
Plugins are not allowed to declare services using interfaces defined in
another plugin. This prevents two plugins from defining a service using
the same interface, and ensures that circular dependencies can only
occur within the same plugin.<br>
<h2><a class="mozTocH2" name="mozTocId749133"></a>2.5 Using Component
Interfaces<br>
</h2>
This example shows how a component can use an interface supplied by its
parent.<br>
<br>
<div style="margin-left: 40px;"><code>public class MyView {</code><br>
<code>&nbsp;&nbsp;&nbsp; private IErrorContext errorContext;</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public MyView(</code><code>Composite parent, </code><code>IErrorContext
errorContext) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; this.errorContext = errorContext;</code><br>
<code></code><br>
<code></code><code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Button errorButton =
new
Button(parent, SWT.PUSH);</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errorButton.setText("Log an
exception");</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
errorButton.addSelectionListener(new
SelectionAdapter() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; public void
widgetSelected(SelectionEvent e) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
try {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp; // Throw a NPE</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp; String myString = null;</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp; String bogusCode = myString.substring(10, 30);</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
} catch (Exception e) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp; // Log the NPE using the error context</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp; &nbsp; errorContext.log(e);</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; });</code><br>
<code></code><code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><code>}</code><br>
<code></code></div>
<code><br>
</code>This view creates a button which, when pressed, will throw a NPE
and log it. The status message will be constructed and logged using the
IErrorContext interface we defined above. The default implementation of
the interface is associated with a
unique component instance, so if we were to create two instances of
MyView we would also end up with two instances of ErrorContext. <br>
<br>
There
is never any ambiguity about which implementation of IErrorContext to
use. If the parent of MyView explicitly supplies an IErrorContext
service, that implementation is used. Otherwise, the unique default
implementation is used. There can never be two global implementations.<br>
<br>
<h2><a class="mozTocH2" name="mozTocId705695"></a>2.6 Lifecycle</h2>
Many components need to do explicit cleanup. Components
that need to perform cleanup will implement the
IDisposable interface. For example, the following component attaches a
listener to a global preference store and detaches it when done.<br>
<br>
<div style="margin-left: 40px;"><code>/**</code><br>
<code>&nbsp;* Provides access to a plugin's preference store in a
manner that
prevents listener leaks.</code><br>
<code>&nbsp;*/</code><br>
<code>public interface IPreferences {</code><br>
<code>&nbsp;&nbsp;&nbsp; public String getString(String prefId);</code><br>
<code>&nbsp;&nbsp;&nbsp; public void setString(String prefId, String
value);</code><br>
<code>&nbsp;&nbsp;&nbsp; public void
addListener(IPropertyChangeListener l);</code><br>
<code>&nbsp;&nbsp;&nbsp; public void
removeListener(IPropertyChangeListener
l);</code><br>
<code>}</code><br>
<code></code><br>
<code>/**</code><br>
<code>&nbsp;* Concrete implementation of the IPreferences interface</code><br>
<code>&nbsp;*/</code><br>
<code>public LocalPreferenceStore implements IPreferences, IDisposable {</code><br>
<code>&nbsp;&nbsp;&nbsp; ListenerList listeners = new ListenerList();</code><br>
<code>&nbsp;&nbsp;&nbsp; Preferences prefs;</code><br>
<code>&nbsp;&nbsp;&nbsp; </code><br>
<code>&nbsp;&nbsp;&nbsp; private class PropertyChangeListener
implements
Preferences.IPropertyChangeListener {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;* @see
org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;*/</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void
propertyChange(Preferences.PropertyChangeEvent event) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
firePropertyChangeEvent(event.getProperty(), event.getOldValue(),
event.getNewValue());</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; PropertyChangeListener listener = new
PropertyChangeListener();</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * Create a wrapper around the given
bundle's
preference store.</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public LocalPreferenceStore(Bundle
pluginBundle) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Plugin plugin =
Platform.getPlugin(pluginBundle.getSymbolicName());</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; prefs =
plugin.getPluginPreferences();</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; prefs.addListener(listener);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; private void firePropertyChange(String name,
Object
oldValue, Object newValue) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; PropertyChangeEvent event =
new
PropertyChangeEvent(this, name, oldValue, newValue);</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Object[] listeners =
this.listeners.getListeners();</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i= 0; i &lt;
listeners.length; i++)</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
((IPropertyChangeListener) listeners[i]).propertyChange(event);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; /**</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * This method will automatically be
called
when the component that uses this adapter is disposed.</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; * It should clean up anything that has
been
allocated by the service.</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; */</code><br>
<code>&nbsp;&nbsp;&nbsp; public void dispose() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; prefs.removeListener(listener);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public String getString(String prefId) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return prefs.getString(prefId);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void setString(String prefId, String
value) {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; prefs.setValue(prefId, value);</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code></div>
<code></code><br>
Similarly, components may implement the IDisposable interface. A
component that implements IDisposable will be disposed before the
objects it depends on, as shown by the following example:<br>
<br>
<div style="margin-left: 40px;"><code>public LifecycleService
implements IDisposable {</code><br>
<code>&nbsp;&nbsp;&nbsp; public LifecycleService() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
System.out.println("LifecycleService
created");</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void dispose() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
System.out.println("LifecycleService
destroyed");</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code><br>
<code>public LifecycleView implements IDisposable {</code><br>
<code>&nbsp;&nbsp;&nbsp; public LifecycleView(LifecycleService service)
{</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; System.out.println("LifecycleView
created");</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code></code><br>
<code>&nbsp;&nbsp;&nbsp; public void dispose() {</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; System.out.println("LifecycleView
destroyed");</code><br>
<code>&nbsp;&nbsp;&nbsp; }</code><br>
<code>}</code><br>
<code></code><br>
</div>
Finally, we could execute the following code to trace when the
LifecycleService is created and destroyed:<br>
<div style="margin-left: 40px;"><br>
IMutableContainerFactory factory =
Components.getFactory().createDerivedFactory();<br>
factory.addComponentImplementation(LifecycleService.class);<br>
<br>
System.out.println("Creating a LifecycleView");<br>
<br>
IContainer viewComponent = factory.createComponent(LifecycleView.class);<br>
viewComponent.dispose();<br>
<br>
System.out.println("Creating two LifecycleViews");<br>
<br>
IContainer viewComponent2 =
factory.createComponent(LifecycleView.class);<br>
IContainer viewComponent3 =
factory.createComponent(LifecycleView.class);<br>
viewComponent3.dispose();<br>
viewComponent2.dispose();<br>
<br>
</div>
The code will generate the following output:<br>
<br>
<div style="margin-left: 40px;">Creating a LifecycleView<br>
LifecycleService created<br>
LifecycleView created<br>
LifecycleView destroyed<br>
LifecycleService destroyed<br>
<br>
Creating two LifecycleViews<br>
LifecycleService created<br>
LifecycleView created<br>
LifecycleService created<br>
LifecycleView created<br>
LifecycleView destroyed<br>
LifecycleService destroyed<br>
LifecycleView destroyed<br>
LifecycleService destroyed<br>
<br>
</div>
<h2><a class="mozTocH2" name="mozTocId543223"></a>2.7 Dynamic Interfaces<br>
</h2>
Component interfaces are dynamic in the sense that they may be
registered or unregistered as their plugins are installed or
uninstalled. If a plugin providing component interface is uninstalled,
that interface will become unavailable and it will no longer be
possible to construct objects that depend on the interface.<br>
<br>
The objects instances themselves are not dynamic. Once an adapter is
created to supply an interface, it will exist for as long as the
component it was created for.
Even if the a plugin stops providing an interface, all instances of
that
interface will continue to exist until disposed. All interfaces used by
a
component will be created before that component, so components do not
need to query for the existence of services or to wait for services
that will be created after-the-fact. <br>
<h2><a class="mozTocH2" name="mozTocId886834"></a>2.8 Optional Interface<br>
</h2>
Sometimes a component does not require an interface but can make use of
it if it exists. This is normally not necessary for any interface
registered through the <code>org.eclipse.core.component.interface</code>
extension point since the default implementation will guarantee that
the interface always exists even if the parent context doesn't know
about it. However, this situation can occur if a parent and child are
communicating with an interface that wasn't originally intended for use
as a component interface, or if the child requires a variable set of
interfaces.<br>
<br>
Note: this pattern doesn't actually allow the component to be used in a
wider context, but it does allow the component to request interfaces
that aren't registered by the normal means.<br>
<br>
This can be done by taking an argument of type
IAdaptable, like this:<br>
<br>
<div style="margin-left: 40px;"><code>public interface INameService {<br>
&nbsp;&nbsp;&nbsp; public String getName();<br>
}<br>
<br>
<br>
/**<br>
&nbsp;* A component with no dependencies, but which can optionally
accept an IMemento for initialization.<br>
&nbsp;*/<br>
public class MyComponent {<br>
<br>
&nbsp;&nbsp;&nbsp; String myName = "default name";<br>
<br>
&nbsp;&nbsp;&nbsp; public MyComponent(IAdaptable optionalInterfaces) {<br>
<br>
</code><code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // Check if an
INameService
service exists.</code><br>
<code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; INameService nameService =
(INameService)optionalInterfaces.getAdapter(INameService.class);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (memento != null) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; myName =
nameService.getName();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; System.out.println("created component
with name = " + myName);<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
</code></div>
We could create the component like this:<br>
<br>
<div style="margin-left: 40px;"><code>// Create a memento with the name
"custom name"<br>
INameService nameService = new INameService() {<br>
&nbsp;&nbsp;&nbsp; public String getName() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return "custom name";<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
// Create a factory which knows about our memento<br>
IMutableContainerFactory context =
Components.getFactory().createDerivedFactory();<br>
context.addComponentInstance(nameService);<br>
<br>
// Use the factory to instantiate MyComponent<br>
IContainer component = context.createContainer(MyComponent.class);<br>
// Will print the message "created component with name = custom name"<br>
component.dispose();</code><br>
<br>
</div>
We can also create the component without the optional INameService:<br>
<br>
<div style="margin-left: 40px;"><code>IContainer component =
Components.getFactory().createContainer(MyComponent.class);<br>
// Will print the message "create component with name = default name"<br>
component.dispose();</code><code></code><br>
</div>
<br>
<br>
<span style="font-weight: bold;">WARNING: </span>This pattern should
be used with care since it adds special
cases to the component code. It is mainly inteded for advanced
situations where a component needs to request an interface that isn't
normally visible in its scope.<br>
<br>
The preferred method of dealing with missing interfaces is to provide a
default implementation, like this:<br>
<br>
<div style="margin-left: 40px;"><code>&lt;extension
point="</code><code>org.eclipse.core.component.interface</code><code>"&gt;</code><br>
<code>&nbsp;&nbsp; &lt;interface
</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp;
class="org.eclipse.ui.DefaultNameService"</code><br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; </code><code>interface="</code><code>org.eclipse.ui.INameService</code><code>"</code><code>&gt;</code><br>
<code>&nbsp;&nbsp; &lt;/interface&gt;</code><br>
<code>&lt;/extension&gt;<br>
<br>
<br>
/**<br>
&nbsp;* Default implementation of INameService that will be used if the
parent doesn't explicitly provide one<br>
&nbsp;*/<br>
class NameService implements INameService {<br>
</code><code>&nbsp;&nbsp;&nbsp; public String getName() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return "default name";<br>
&nbsp;&nbsp;&nbsp; }<br>
</code><code>}<br>
<br>
</code><code>/**<br>
&nbsp;* A component with no dependencies, but which can optionally
accept an INameService for initialization.<br>
&nbsp;*/<br>
public class MyComponent {<br>
<br>
&nbsp;&nbsp;&nbsp; String myName;<br>
<br>
&nbsp;&nbsp;&nbsp; public MyComponent(INameService nameService) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; myName = nameService.getName();<br>
</code><code></code><code><br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; System.out.println("created component
with name = " + myName);<br>
&nbsp;&nbsp;&nbsp; }<br>
}</code><code><br>
</code></div>
<br>
With this approach, it is still possible to create a MyComponent with
or without an INameService, but the special-case code for handling
missing interfaces is written once inside the default implementation
rather than many times inside each component that uses
the interface.<br>
<h2><a class="mozTocH2" name="mozTocId578639"></a>2.8 Component Scopes</h2>
Scopes are a way to determine what interfaces can be used in the
constructor of a component. At some point, a programmer is going to ask
"What interfaces am I allowed to pass into the constructor of my view?"
Ultimately, this could be determined by examining the dependencies
between each service, but it is not reasonable to expect a programmer
to have this level of knowledge of the dependencies between services.<br>
<br>
Scopes limit the dependencies between services in order to make this
question easier to answer. For example, views are allowed to use any
service in the "/plugin/part/view" scope. This makes it easy to write a
PDE extension which displays the list of interfaces available to a
views. <br>
<br>
The only difference between scopes is how much context the components
are allowed to expect. For example, components in the <span
 style="font-style: italic;">plugin</span> scope will be given a plugin
Bundle and components in the <span style="font-style: italic;">plugin/part</span>
scope need to be associated with a particular SWT Composite. Components
may depend on services in the same scope or in a
more general scope. It is still possible for Components to reference
services in a more specific scope, but they must do so as an optional
interface (as described in section 2.7).<span
 style="font-style: italic;"></span><br>
<br>
Eclipse defines the following standard scopes.<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
 cellspacing="2">
  <tbody>
    <tr>
      <td style="vertical-align: top;">Scope path<br>
      </td>
      <td style="vertical-align: top;">Required context<br>
      </td>
      <td style="vertical-align: top;">Description<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/<br>
      </td>
      <td style="vertical-align: top;">None<br>
      </td>
      <td style="vertical-align: top;">Any service that omits the <span
 style="font-style: italic;">scope</span> attribute automatically
belongs to the global scope. Services in the global scope can be used
by any other component, but may only depend on other global services.
Global services are not given any context from the application.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin<br>
      </td>
      <td style="vertical-align: top;">Bundle<br>
      </td>
      <td style="vertical-align: top;">Components in the /plugin scope
are created in the context of a plugin bundle. All executable
extensions (any component created using an extension point) belong to
the plugin scope. Components in this scope can reference their own
plugin Bundle in their constructor. Services can reference the Bundle
associated with the component that requested them.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin/part<br>
      </td>
      <td style="vertical-align: top;">Bundle, Composite<br>
      </td>
      <td style="vertical-align: top;">Components in the /plugin/part
scope are associated with an SWT Composite. Components in this scope
are given their
own SWT Composite. They may change the layout on the given Composite,
but may not change its layout data. The composite will be managed as a
service, so the component does not need to dispose it. Components in
this scope may be used as editors, views, or both.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin/part/view<br>
      </td>
      <td style="vertical-align: top;">Bundle,<br>
Composite,<br>
IWorkbenchPage<br>
      </td>
      <td style="vertical-align: top;">All views belong to this scope.
They are given the IConfigurationElement containing their extension
markup, and an IWorkbenchPage.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin/part/editor<br>
      </td>
      <td style="vertical-align: top;">Bundle,<br>
Composite,<br>
IWorkbenchPage,<br>
IEditorInput<br>
      </td>
      <td style="vertical-align: top;">All editors belong to this
scope. They are given the IConfigurationElement containing their
extension markup, an IWorkbenchPage, and the IEditorInput containing
their input.<br>
      </td>
    </tr>
  </tbody>
</table>
<br>
These scopes should be sufficient for most situations. However, some
plugins may wish to create new scopes in order to pass additional
context to the objects in an extension point they provided.<br>
<br>
Any plugin that defines its own scopes must include its fully qualified
plugin ID as part of the scope path. For example, if the plugin
org.eclipse.myplugin extends the /plugin/part/editor scope, the new
scope name would look like
/plugin/part/editor/org.eclipse.myplugin.scopename. All scope paths
that do not contain a period (.) are reserved by the framework.<br>
<br>
It is never a breaking change to move a service into a more general
scope. However, it is always a breaking change to move a service into a
more specific scope. A service interface may only exist in one scope.<br>
<h2><a class="mozTocH2" name="mozTocId762751"></a>2.9 Shared Adapters</h2>
Normally, a new instance of a default interface implementation is
created for each component that requests it. This allows the adapter to
keep some state associated with the component and to clean up resources
once they are no longer needed by the component. However, some
interface do not need any state or expose any API that could be used to
create a leak. For example, the IErrorContext interface in section 2.4
could safely share one instance between all components in the same
plugin. In order to reduce memory consumption, the component API should
support the notion of a shared adapter. A shared adapter will be reused
in the broadest possible context permitted by its scope. For example,
an adapter for an interface in the global scope would become a
singleton, shared adapters in the plugin scope will have at most one
instance per plugin, and the shared flag will be ignored in the
/plugin/part scope.<br>
<br>
This is intended as a future optimization, and will not be included in
the initial version of the component framework<br>
<br>
<h1><a class="mozTocH1" name="mozTocId707022"></a>3.0 Views and Editors
as Components</h1>
This section describes how the workbench uses the component framework
to create editors and views.<br>
<br>
<h2><a class="mozTocH2" name="mozTocId125361"></a>3.1 Interfaces
offered by the workbench</h2>
Parent interfaces: (Interfaces given to a component as arguments in its
constructor)<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
 cellspacing="2">
  <tbody>
    <tr>
      <td style="vertical-align: top;">Scope<br>
      </td>
      <td style="vertical-align: top;">Interface<br>
      </td>
      <td style="vertical-align: top;">Description<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin<br>
      </td>
      <td style="vertical-align: top;">IErrorContext<br>
      </td>
      <td style="vertical-align: top;">Provides facilities for logging
exceptions<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin<br>
      </td>
      <td style="vertical-align: top;">ISwtResources<br>
      </td>
      <td style="vertical-align: top;">Provides facilities for
allocating SWT resources such as Fonts, Images, and Colors<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/<br>
      </td>
      <td style="vertical-align: top;">INameable<br>
      </td>
      <td style="vertical-align: top;">Parts can use this service to
change their name, content description, title image, and tooltip. The
default implementation ignores all method calls.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/<br>
      </td>
      <td style="vertical-align: top;">IMemento<br>
      </td>
      <td style="vertical-align: top;">Parts will receive a memento
which they can use to load previously-saved state<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin<br>
      </td>
      <td style="vertical-align: top;">IPartFactory<br>
      </td>
      <td style="vertical-align: top;">Interface that can be used to
create child views, editors, and other UI parts<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin/part<br>
      </td>
      <td style="vertical-align: top;">IActionBars2<br>
      </td>
      <td style="vertical-align: top;">Interface used to add to the
toolbar, cool bar, etc. Currently exposed on the view site.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;"><br>
      </td>
      <td style="vertical-align: top;"><br>
      </td>
      <td style="vertical-align: top;"><br>
      </td>
    </tr>
  </tbody>
</table>
<br>
Child interfaces: (Services that a component offers to its parent -
either by implementing directly or as an adapter)<br>
<br>
<table style="text-align: left; width: 1550px; height: 88px;" border="1"
 cellpadding="2" cellspacing="2">
  <tbody>
    <tr>
      <td style="vertical-align: top;">Scope<br>
      </td>
      <td style="vertical-align: top;">Interface<br>
      </td>
      <td style="vertical-align: top;">Description<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/plugin/part<br>
      </td>
      <td style="vertical-align: top;">IFocusable<br>
      </td>
      <td style="vertical-align: top;">Parts can implement this service
to allow their parent<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/<br>
      </td>
      <td style="vertical-align: top;">IMultiPart<br>
      </td>
      <td style="vertical-align: top;">Parts should implement this if
they contain other parts and have the notion of an "active" child.
Other services can use this service if their default implementation
should redirect to the active child.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">/<br>
      </td>
      <td style="vertical-align: top;">IPersistable<br>
      </td>
      <td style="vertical-align: top;">Parts may implement this
interface if they wish to save their state between sessions.<br>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;"><br>
      </td>
      <td style="vertical-align: top;"><br>
      </td>
      <td style="vertical-align: top;"><br>
      </td>
    </tr>
  </tbody>
</table>
<br>
<br>
<h3><a class="mozTocH2" name="mozTocId163729"></a>3.1.1 IMultiPart:
Redirecting
adapters from the active child<br>
</h3>
In UI code, it is common to create aggregate components that have an
"active" child. This section suggests a general pattern for redirecting
components in this way. Many of the adapters that the aggregate offers
its
parent will redirect their implementation to the active child. The
aggregate itself will know
how to select its active child, but it may not know about all the
interfaces that need to be redirected in this manner. The default
implementation of an interface determines how it should be redirected.<br>
<br>
This can be shown using a concrete example. Workbench parts
offer an IFocusable adapter to their parent that allows their parent to
give them focus. <br>
<br>
<code></code>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* Parts can implement this interface if they wish to overload the
default<br>
&nbsp;* setFocus behavior.<br>
&nbsp;*/<br>
public interface IFocusable {<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* Gives focus to the part<br>
&nbsp;&nbsp;&nbsp; &nbsp;*/<br>
&nbsp;&nbsp;&nbsp; public void setFocus();<br>
}</code><br>
<br>
</div>
This interface should be multiplexed by default. For example, if we
call setFocus() on a multi-page editor that doesn't explicitly
implement the IFocusable interface, it should redirect focus to its
active child. If the part doesn't have an active child, focus should go
directly to the part's main control. To supply this default behavior,
we provide a default implementation of IFocusable:<br>
<br>
<code></code>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* Default implementation of the IFocusable service. If a part
doesn't explicitly<br>
&nbsp;* provide an adapter for IFocusable, this implementation will be
used.<br>
&nbsp;*/<br>
public class DefaultFocusable implements IFocusable {<br>
<br>
&nbsp;&nbsp;&nbsp; private Composite control;<br>
&nbsp;&nbsp;&nbsp; private IMultiPart activePart;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* Creates the default implementation of
IFocusable, given the main control<br>
&nbsp;&nbsp;&nbsp; &nbsp;* of the part and an IMultiPart that can be
queried for the active child.<br>
&nbsp;&nbsp;&nbsp; &nbsp;* <br>
&nbsp;&nbsp;&nbsp; &nbsp;* @param toGiveFocus main control of the pane<br>
&nbsp;&nbsp;&nbsp; &nbsp;* @param activePartProvider multiplexer that
returns the active part<br>
&nbsp;&nbsp;&nbsp; &nbsp;*/<br>
&nbsp;&nbsp;&nbsp; public DefaultFocusable(Composite toGiveFocus,
IMultiPart activePartProvider) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; control = toGiveFocus;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; activePart = activePartProvider;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * First, try to give focus to the active
child. If there is no active child, give focus to<br>
&nbsp;&nbsp;&nbsp;&nbsp; * the main control.<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public void setFocus() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // If this part has the notion of
an active child, give that child focus<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Object current =
activePart.getCurrent();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (current != null) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; IFocusable
focusable = (IFocusable)Components.getAdapter(current,
IFocusable.class);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (focusable
!= null) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; focusable.setFocus();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // If the part has no children,
then give focus to the part itself.&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; control.setFocus();<br>
&nbsp;&nbsp;&nbsp; }<br>
}</code><br>
<br>
</div>
Here is the XML markup to register the interface:<br>
<br>
<div style="margin-left: 40px;"><code>&lt;service<br>
&nbsp;&nbsp;&nbsp;
interface="org.eclipse.ui.workbench.services.IFocusable"<br>
&nbsp;&nbsp;&nbsp;
class="org.eclipse.ui.internal.part.serviceimplementation.DefaultFocusable<br>
&nbsp;&nbsp;&nbsp; childadapter="true"<br>
&nbsp;&nbsp;&nbsp; scope="plugin/part"/&gt;</code><code></code><br>
</div>
<br>
All of the interfaces we have looked at so far have been offered by a
parent for use in a child's constructor. In this case, the interface is
offered as an adapter on the child to be used by the parent. In both
cases, we support the notion of a default implementation that is
declared through XML. Any service that should be redirected based on
the active child will take IMultiPart in its constructor. Here is an
example part that supports
multiplexing:<br>
<code><br>
</code>
<div style="margin-left: 40px;"><code>/**<br>
&nbsp;* Part that explicitly implements IFocusable.<br>
&nbsp;*/<br>
public class Page implements IFocusable {<br>
&nbsp;&nbsp;&nbsp; Text textField;<br>
<br>
&nbsp;&nbsp;&nbsp; public Page(Composite control) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; textField = new Text(control, SWT.NONE);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; public void setFocus() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; textField.setFocus();<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
/**<br>
&nbsp;* Non-multiplexing part that relies on the DefaultFocusable
service<br>
&nbsp;* to give focus to its composite.<br>
&nbsp;*/<br>
public class Page2 {<br>
&nbsp;&nbsp;&nbsp; Text textField;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; public Page(Composite control) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; textField = new Text(control, SWT.NONE);<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
/**<br>
&nbsp;* Multiplexing part that contains a Page, a Page2, and a checkbox.<br>
&nbsp;* When the checkbox is selected, the first page will be active.
When the<br>
&nbsp;* checkbox is deselected, the second page will be active. Calling
setFocus<br>
&nbsp;* on the MultiplexingView will always give focus to the active
page.<br>
&nbsp;*/<br>
public class MultiplexingView implements IDisposable, IAdaptable {<br>
&nbsp;&nbsp;&nbsp; private IContainer page1;<br>
&nbsp;&nbsp;&nbsp; private IContainer page2;<br>
<br>
&nbsp;&nbsp;&nbsp; // Helper class that implements the IMultiPart
interface<br>
&nbsp;&nbsp;&nbsp; private Multiplexer multiplexer = new Multiplexer();<br>
&nbsp;&nbsp;&nbsp; private Button checkBox;<br>
<br>
&nbsp;&nbsp;&nbsp; public MultiplexingView(Composite myControl) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; myControl.setLayout(new RowLayout());<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; checkBox = new Button(myControl,
SWT.CHECK);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; checkBox.addSelectionListener(new
SelectionAdapter() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; public void
widgetSelected(SelectionEvent e) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
updateActivePart();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; });<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; checkBox.setText("Activate part 1");<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // Create the child controls<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; IMutableComponentFactory childFactory =
Components.getFactory().createDerivedFactory();<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // Use the CompositeAdapter class we
created earlier in order to provide each page<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // with its own control.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; childFactory.addComponentInstance(new
CompositeAdapter(myControl));<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; page1 =
childFactory.createContainer(Page.class);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; page2 =
childFactory.createContainer(Page2.class);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; // Activate the initial part<br>
</code><code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; updateActivePart();</code><br>
<code>&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; private final void updateActivePart() {<br>
</code><code>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if
(checkBox.getSelection()) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
multiplexer.setCurrent(page1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
multiplexer.setCurrent(page2);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</code><br>
<code>&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * In order to indicate that this is a
multiplexing part, we need to implement<br>
&nbsp;&nbsp;&nbsp;&nbsp; * the IMultiplexer adapter. We simply redirect
to the multiplexer object.<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public Object getAdapter(Class adapterType) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if (adapterType == IMultiplexer.class) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; return multiplexer;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp;&nbsp; * Release any resources allocated in the
constructor<br>
&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp; public void dispose() {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; page1.dispose();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; page2.dispose();<br>
&nbsp;&nbsp;&nbsp; }<br>
}</code><br>
</div>
<br>
Notice that MultiplexingView itself doesn't know about the IFocusable
interface, however if we were to create a MultiplexingView and ask its
container for an IFocusable interface, we would get an interface that
behaves as expected. <br>
<br>
<div style="margin-left: 40px;"><code></code><code>// Stupid example
that creates a MultiplexingView, gives it focus, then destroys it<br>
<br>
// Create a MultiplexingView</code><br>
<code>IMutableComponentFactory childFactory =
Components.getFactory().createDerivedFactory();<br>
</code><code>childFactory.addComponentInstance(new
CompositeAdapter(myControl));<br>
<br>
IContainer viewContainer =
childFactory.createContainer(MultiplexingView.class);<br>
<br>
// Give focus to the active part<br>
IFocusable focusable = viewContainer.getAdapter(IFocusable.class);<br>
focusable.setFocus();<br>
</code><code></code><code><br>
// Destroy the view<br>
viewContainer.dispose();<br>
</code><code></code></div>
<code>&nbsp;&nbsp;&nbsp; <br>
</code>This example also shows how the same default implementation can
work for both
multiplexing and non-multiplexing parts. The Page2 class doesn't
implement IFocusable or IMultiPart, but we are still able to
ask for an IFocusable interface and use it to give focus to the part.<br>
<span style="font-weight: bold;"><br>
</span><span style="font-weight: bold;"></span>
<h3><a class="mozTocH3" name="mozTocId483376"></a>3.1.2 INameable:
Changing the name of a part</h3>
In order to change their name, existing parts need to implement a set
of get methods, maintain a listener list, and send notifications when
their name changes. Component-based parts will change their name by
using an INameable interface provided by their parent. INameable looks
like this:<br>
<br>
<div style="margin-left: 40px;"><code>public interface INameable {<br>
&nbsp;&nbsp;&nbsp; public void setName(String newName);<br>
&nbsp;&nbsp;&nbsp; public void setContentDescription(String
contentDescription);<br>
&nbsp;&nbsp;&nbsp; public void setImage(Image theImage);<br>
&nbsp;&nbsp;&nbsp; public void setTooltip(String toolTip);<br>
}<br>
<br>
</code></div>
For example, a view could set its name like this:<br>
<br>
<div style="margin-left: 40px;"><code>public class MyView {<br>
&nbsp;&nbsp;&nbsp; public MyView(Composite parent, INameable name) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; name.setName("Some tab text");<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
</code></div>
If a parent cares about the names of its children, it should provide an
implementation of INameable that reacts when the child changes its
name. Otherwise, the child will be given a default implementation of
INameable that ignores all method calls. This eliminates the need to
attach listeners to views.<br>
<h3><a class="mozTocH3" name="mozTocId969580"></a>3.1.3 IPartFactory:
Creating child parts<br>
</h3>
Any part that wants to create other nested parts would use an
IPartFactory interface.<br>
<br>
<div style="margin-left: 40px;"><code>public interface IPartFactory {<br>
&nbsp;&nbsp;&nbsp; public IContainer createView(String viewId,
Composite parentComposite, IWorkbenchPage page, IContainerFactory
services);<br>
&nbsp;&nbsp;&nbsp; public IContainer createEditor(String editorId,
Composite parentComposite, IWorkbenchPage page, </code><code>IEditorInput
input, </code><code>IContainerFactory services);<br>
&nbsp;&nbsp;&nbsp; public IContainer createPart(String partId,
Composite parentComposite, IContainerFactory services);<br>
}</code><br>
<br>
<br>
</div>
<div style="margin-left: 40px;"><code></code><code></code></div>
<span style="font-weight: bold;"></span>
</body>
</html>