| 12 |
style="font-weight: bold;">Component Framework Proposal</span></font><br> |
style="font-weight: bold;">Component Framework Proposal</span></font><br> |
| 13 |
</div> |
</div> |
| 14 |
<br> |
<br> |
| 15 |
<div style="text-align: center;">Revision 1.0.3<br> |
<div style="text-align: center;">Draft<br> |
| 16 |
|
Revision 1.0.4<br> |
| 17 |
By Stefan Xenos and Nick Edgar<br> |
By Stefan Xenos and Nick Edgar<br> |
| 18 |
Last modified 2004/11/02<br> |
Last modified 2004/11/05<br> |
| 19 |
</div> |
</div> |
| 20 |
<br> |
<br> |
| 21 |
<br> |
<br> |
| 26 |
Introduction |
Introduction |
| 27 |
</a> |
</a> |
| 28 |
<ul> |
<ul> |
| 29 |
<li><a href="#mozTocId29093">1.1 Robustness / leak proofing |
<li><a href="#mozTocId619855">1.1 Understanding the problem</a></li> |
| 30 |
|
<li><a href="#mozTocId340323">1.2 Requirements |
| 31 |
|
</a> |
| 32 |
|
<ul> |
| 33 |
|
<li><a href="#mozTocId29093">1.2.1 Robustness / |
| 34 |
|
leak |
| 35 |
|
proofing |
| 36 |
</a></li> |
</a></li> |
| 37 |
<li><a href="#mozTocId223982">1.2 Nesting of components</a></li> |
<li><a href="#mozTocId223982">1.2.2 Nesting of |
| 38 |
<li><a href="#mozTocId634024">1.3 Creating parts outside the |
components</a></li> |
| 39 |
workbench</a></li> |
<li><a href="#mozTocId634024">1.2.3 Creating parts |
| 40 |
<li><a href="#mozTocId800379">1.4 Scalability</a></li> |
outside the workbench</a></li> |
| 41 |
<li><a href="#mozTocId866479">1.5 Ease of use |
<li><a href="#mozTocId800379">1.2.4 Scalability</a></li> |
| 42 |
|
<li><a href="#mozTocId866479">1.2.5 Ease of use |
| 43 |
</a></li> |
</a></li> |
| 44 |
</ul> |
</ul> |
| 45 |
</li> |
</li> |
| 46 |
<li><a href="#mozTocId416167">2.0 Component Framework |
</ul> |
| 47 |
|
</li> |
| 48 |
|
<li><a href="#mozTocId416167">2.0 Component |
| 49 |
|
Framework |
| 50 |
</a> |
</a> |
| 51 |
<ul> |
<ul> |
| 52 |
<li><a href="#mozTocId489102">2.1 Instantiating a view |
<li><a href="#mozTocId489102">2.1 Instantiating a |
| 53 |
|
view |
| 54 |
</a></li> |
</a></li> |
| 55 |
<li><a href="#mozTocId717633">2.2 Instantiating components in |
<li><a href="#mozTocId717633">2.2 Instantiating |
| 56 |
general |
components in general |
| 57 |
</a></li> |
</a></li> |
| 58 |
<li><a href="#mozTocId450231">2.3 Creating dependent components |
<li><a href="#mozTocId450231">2.3 Creating |
| 59 |
on demand </a></li> |
dependent components on demand </a></li> |
| 60 |
<li><a href="#mozTocId928619">2.4 Declaring Global Services |
<li><a href="#mozTocId928619">2.4 Declaring Component Interfaces</a></li> |
| 61 |
</a></li> |
<li><a href="#mozTocId749133">2.5 Using Component Interfaces</a></li> |
|
<li><a href="#mozTocId749133">2.5 Using services</a></li> |
|
| 62 |
<li><a href="#mozTocId705695">2.6 Lifecycle</a></li> |
<li><a href="#mozTocId705695">2.6 Lifecycle</a></li> |
| 63 |
<li><a href="#mozTocId543223">2.7 Dynamic Services</a></li> |
<li><a href="#mozTocId543223">2.7 Dynamic Interfaces</a></li> |
| 64 |
<li><a href="#mozTocId886834">2.8 Optional Services</a></li> |
<li><a href="#mozTocId886834">2.8 Optional Interface |
| 65 |
<li><a href="#mozTocId163729">2.9 Multiplexing services</a></li> |
</a></li> |
| 66 |
|
<li><a href="#mozTocId578639">2.8 Component Scopes</a></li> |
| 67 |
|
<li><a href="#mozTocId762751">2.9 Shared Adapters</a></li> |
| 68 |
|
</ul> |
| 69 |
|
</li> |
| 70 |
|
<li><a href="#mozTocId707022">3.0 Views and Editors |
| 71 |
|
as Components</a> |
| 72 |
|
<ul> |
| 73 |
|
<li><a href="#mozTocId125361">3.1 Interfaces offered by the |
| 74 |
|
workbench</a> |
| 75 |
|
<ul> |
| 76 |
|
<li><a href="#mozTocId163729">3.1.1 IMultiPart: Redirecting |
| 77 |
|
adapters from the active child |
| 78 |
|
</a></li> |
| 79 |
|
<li><a href="#mozTocId483376">3.1.2 INameable: Changing the |
| 80 |
|
name of a part</a></li> |
| 81 |
|
<li><a href="#mozTocId969580">3.1.3 IPartFactory: Creating |
| 82 |
|
child parts</a></li> |
| 83 |
|
</ul> |
| 84 |
|
</li> |
| 85 |
</ul> |
</ul> |
| 86 |
</li> |
</li> |
|
<li><a href="#mozTocId707022">3.0 Views and Editors as Components</a></li> |
|
| 87 |
</ul> |
</ul> |
| 88 |
<br> |
<br> |
| 89 |
<h1><a class="mozTocH1" name="mozTocId511305"></a>1.0 Introduction<br> |
<h1><a class="mozTocH1" name="mozTocId511305"></a>1.0 Introduction<br> |
| 104 |
third section describes how the workbench will use the component |
third section describes how the workbench will use the component |
| 105 |
framework for views and editors.<br> |
framework for views and editors.<br> |
| 106 |
<br> |
<br> |
| 107 |
|
<h2><a class="mozTocH2" name="mozTocId619855"></a>1.1 Understanding the |
| 108 |
|
problem</h2> |
| 109 |
|
This section explains why the component framework is needed to support |
| 110 |
|
nested parts. We will show the problems involved in designing an |
| 111 |
|
extensible Site interface, and will show how they can be solved using |
| 112 |
|
the patterns in the component framework. Skip to the next sections if |
| 113 |
|
you don't need convincing and just want to see the specification. |
| 114 |
|
IMPORTANT NOTE: |
| 115 |
|
the code examples in this section are only intended to illustrate |
| 116 |
|
patterns and do not reflect the actual implementation<br> |
| 117 |
|
<br> |
| 118 |
|
Currently, parts communicate with their parent through their site. The |
| 119 |
|
site provides the view with access to the outside world. In general, it |
| 120 |
|
is better to provide new API on the part's site than have the part |
| 121 |
|
reach to some global object, since the site can provide some context |
| 122 |
|
and can manage resources allocated to the part.<br> |
| 123 |
|
<br> |
| 124 |
|
Here is a simplified version of the View and Site interface. We've |
| 125 |
|
omitted most of the details. The important part is that the View is |
| 126 |
|
given a Site when it is initialized, it uses various methods on the |
| 127 |
|
Site throughout its life, and the Site has a dispose() method that can |
| 128 |
|
clean up after the View.<br> |
| 129 |
|
<code><br> |
| 130 |
|
</code> |
| 131 |
|
<div style="margin-left: 40px;"><code>/**<br> |
| 132 |
|
* A view's main interface to the world.<br> |
| 133 |
|
*/<br> |
| 134 |
|
public class Site {<br> |
| 135 |
|
/**<br> |
| 136 |
|
* Create a view site, given the plugin that |
| 137 |
|
contains the implementation for the view<br> |
| 138 |
|
*/<br> |
| 139 |
|
public Site(Plugin viewPlugin) {<br> |
| 140 |
|
}<br> |
| 141 |
|
<br> |
| 142 |
|
/**<br> |
| 143 |
|
* Return the view's ID<br> |
| 144 |
|
*/<br> |
| 145 |
|
public String getId() {...};<br> |
| 146 |
|
<br> |
| 147 |
|
public IActionBars getActionBars() {...};<br> |
| 148 |
|
<br> |
| 149 |
|
/**<br> |
| 150 |
|
* Clean up any leftover resources allocated by |
| 151 |
|
the site<br> |
| 152 |
|
*/<br> |
| 153 |
|
public void dispose() {<br> |
| 154 |
|
};<br> |
| 155 |
|
}<br> |
| 156 |
|
<br> |
| 157 |
|
/**<br> |
| 158 |
|
* Base class for all views.<br> |
| 159 |
|
*/<br> |
| 160 |
|
public abstract class View {<br> |
| 161 |
|
private Site mySite;<br> |
| 162 |
|
<br> |
| 163 |
|
public View(Site viewSite) {<br> |
| 164 |
|
mySite = viewSite;<br> |
| 165 |
|
}<br> |
| 166 |
|
<br> |
| 167 |
|
public Site getSite() {<br> |
| 168 |
|
return mySite;<br> |
| 169 |
|
}<br> |
| 170 |
|
<br> |
| 171 |
|
public abstract String getTitle();<br> |
| 172 |
|
<br> |
| 173 |
|
public void dispose() {};<br> |
| 174 |
|
}<br> |
| 175 |
|
<br> |
| 176 |
|
/**<br> |
| 177 |
|
* A factory that can create views by ID.<br> |
| 178 |
|
*/<br> |
| 179 |
|
public ViewFactory {<br> |
| 180 |
|
public static View createView(String |
| 181 |
|
viewExtensionId, Site viewSite) {<br> |
| 182 |
|
//... create a view and return it<br> |
| 183 |
|
}<br> |
| 184 |
|
}<br> |
| 185 |
|
</code></div> |
| 186 |
|
<br> |
| 187 |
|
Anyone that wants to instantiate a view would need to create an |
| 188 |
|
instance of Site and create the view by calling ViewFactory.createView. |
| 189 |
|
It would be possible to subclass Site in order to provide the part with |
| 190 |
|
additional context. For example, a subclass of Site could overload |
| 191 |
|
getActionBars() to substitute a different implementation of IActionBars |
| 192 |
|
to be used by the view. <br> |
| 193 |
|
<br> |
| 194 |
|
One of the problems with using the Site as the main interface to a view |
| 195 |
|
is that we continually need to add new methods to the Site base class. |
| 196 |
|
For example, we might decide to add a logError method that allows views |
| 197 |
|
to log exceptions to their plugin log without needing to reach to their |
| 198 |
|
Plugin object or worry about constructing IStatus instances with the |
| 199 |
|
correct plugin ID.<br> |
| 200 |
|
<br> |
| 201 |
|
<div style="margin-left: 40px;"><code>/**</code><br> |
| 202 |
|
<code> * A view's main interface to the world.</code><br> |
| 203 |
|
<code> */</code><br> |
| 204 |
|
<code>public class Site {<br> |
| 205 |
|
Plugin plugin;<br> |
| 206 |
|
<br> |
| 207 |
|
</code><code></code><code> public Site(Plugin |
| 208 |
|
viewPlugin) {<br> |
| 209 |
|
plugin = viewPlugin;<br> |
| 210 |
|
}<br> |
| 211 |
|
<br> |
| 212 |
|
// ...all other Site methods omitted...<br> |
| 213 |
|
<br> |
| 214 |
|
</code><code> public void logError(Throwable t) {<br> |
| 215 |
|
plugin.getLog().log(new Status(..., t));<br> |
| 216 |
|
};<br> |
| 217 |
|
</code><code>}</code><br> |
| 218 |
|
</div> |
| 219 |
|
<br> |
| 220 |
|
The site could also provide the view with localized ways to allocate |
| 221 |
|
resources. For example, if the view could allocate Images through its |
| 222 |
|
site, the Site could guarantee that the images would be cleaned up |
| 223 |
|
properly when the view is destroyed.<br> |
| 224 |
|
<div style="margin-left: 40px;"><code><br> |
| 225 |
|
/**</code><br> |
| 226 |
|
<code> |
| 227 |
|
* A view's main interface to the world.</code><br> |
| 228 |
|
<code> |
| 229 |
|
*/</code><br> |
| 230 |
|
<code> |
| 231 |
|
public class Site {<br> |
| 232 |
|
<br> |
| 233 |
|
// .... everything in the above version of Site plus |
| 234 |
|
this:<br> |
| 235 |
|
<br> |
| 236 |
|
Map allocatedImages = new HashMap();<br> |
| 237 |
|
<br> |
| 238 |
|
public Image createImage(ImageDescriptor toCreate) {<br> |
| 239 |
|
Image image = |
| 240 |
|
toCreate.createImage(true);<br> |
| 241 |
|
allocatedImages.put(toCreate, image);<br> |
| 242 |
|
return image;<br> |
| 243 |
|
}<br> |
| 244 |
|
<br> |
| 245 |
|
public void destroyImage(ImageDescriptor toDestroy) {<br> |
| 246 |
|
Image image = |
| 247 |
|
allocatedImages.get(toDestroy);<br> |
| 248 |
|
if (image != null) {<br> |
| 249 |
|
|
| 250 |
|
allocatedImages.remove(toDestroy);<br> |
| 251 |
|
image.dispose();<br> |
| 252 |
|
}<br> |
| 253 |
|
}<br> |
| 254 |
|
<br> |
| 255 |
|
public void dispose() {<br> |
| 256 |
|
Collection values = |
| 257 |
|
allocatedImages.getValueSet();<br> |
| 258 |
|
Iterator iter = values.iterator();<br> |
| 259 |
|
while (iter.hasNext()) {<br> |
| 260 |
|
Image img = |
| 261 |
|
(Image)iter.next();<br> |
| 262 |
|
img.dispose();<br> |
| 263 |
|
}<br> |
| 264 |
|
}</code><code><br> |
| 265 |
|
</code><code> |
| 266 |
|
}<br> |
| 267 |
|
<br> |
| 268 |
|
</code></div> |
| 269 |
|
In order to provide the best protection against leaks, new API should |
| 270 |
|
use this pattern as much as possible for views. The obvious problems |
| 271 |
|
with this are:<br> |
| 272 |
|
<ol> |
| 273 |
|
<li>Whoever implements the Site class can't possibly know about every |
| 274 |
|
type of resource that might be allocated by every view</li> |
| 275 |
|
<li>The Site interface would become ridiculously large and |
| 276 |
|
complicated.<br> |
| 277 |
|
</li> |
| 278 |
|
</ol> |
| 279 |
|
It would be possible to work around this by writing new subclasses of |
| 280 |
|
Site that add new methods, but then Views that use the new APIs would |
| 281 |
|
not function properly when given a different Site implementation. The |
| 282 |
|
ideal solution would allow plugins to contribute new default behavior |
| 283 |
|
to the Site base class, and only require the Site class to be |
| 284 |
|
subclassed when this behavior needs to be specialized. This can be |
| 285 |
|
achieved by making Site adaptable. Rather than always adding new |
| 286 |
|
methods to Site, plugins couldcontribute adapters. Subclasses of site |
| 287 |
|
would still be able to override the default adapter behavior by |
| 288 |
|
explicitly implementing the adapter interface, but parts that use the |
| 289 |
|
adapter would no longer be tied to a particular Site implementation.<br> |
| 290 |
|
<br> |
| 291 |
|
Here is an example that demonstrates the pattern:<br> |
| 292 |
|
<br> |
| 293 |
|
<div style="margin-left: 40px;"><code>/**</code><br> |
| 294 |
|
<code> |
| 295 |
|
* Adapter for a view site that allows allocation/deallocation of |
| 296 |
|
images</code><br> |
| 297 |
|
<code> |
| 298 |
|
*/</code><br> |
| 299 |
|
<code> |
| 300 |
|
public interface IImageAllocator {<br> |
| 301 |
|
public Image createImage(ImageDescriptor toCreate);<br> |
| 302 |
|
public void destroyImage(ImageDescriptor toDestroy);<br> |
| 303 |
|
</code><code>}<br> |
| 304 |
|
<br> |
| 305 |
|
/**<br> |
| 306 |
|
* Implementation of the image allocator adapter provided via XML<br> |
| 307 |
|
* by some plugin.<br> |
| 308 |
|
*/<br> |
| 309 |
|
public class ImageAllocator implements IImageAllocator, IDisposable {<br> |
| 310 |
|
</code><code>public Image |
| 311 |
|
createImage(ImageDescriptor toCreate) {<br> |
| 312 |
|
...<br> |
| 313 |
|
};<br> |
| 314 |
|
<br> |
| 315 |
|
public void destroyImage(ImageDescriptor toDestroy) {<br> |
| 316 |
|
...<br> |
| 317 |
|
};<br> |
| 318 |
|
<br> |
| 319 |
|
public void dispose() {<br> |
| 320 |
|
// Dispose any images leaked through |
| 321 |
|
createImage<br> |
| 322 |
|
};<br> |
| 323 |
|
</code><code>}<br> |
| 324 |
|
<br> |
| 325 |
|
/**<br> |
| 326 |
|
* Next attempt at a site interface<br> |
| 327 |
|
*/<br> |
| 328 |
|
public class Site implements IAdaptable {<br> |
| 329 |
|
<br> |
| 330 |
|
List disposableAdapters = new ArrayList();<br> |
| 331 |
|
<br> |
| 332 |
|
public Object getAdapter(Class adapterType) {<br> |
| 333 |
|
</code><code> Object result = //</code><code>...some |
| 334 |
|
magic that looks through the adapter extension point and<br> |
| 335 |
|
|
| 336 |
|
//creates an instance of ImageAllocator<br> |
| 337 |
|
<br> |
| 338 |
|
if (adapter instanceof IDisposable) {<br> |
| 339 |
|
|
| 340 |
|
disposableAdapters.add(adapter);<br> |
| 341 |
|
}<br> |
| 342 |
|
<br> |
| 343 |
|
return result;<br> |
| 344 |
|
}<br> |
| 345 |
|
<br> |
| 346 |
|
/**<br> |
| 347 |
|
* Allow all the adapters to clean up anything |
| 348 |
|
they allocated.<br> |
| 349 |
|
*/<br> |
| 350 |
|
public void dispose() {<br> |
| 351 |
|
Iterator iter = |
| 352 |
|
disposableAdapters.iterator();<br> |
| 353 |
|
while(iter.hasNext()) {<br> |
| 354 |
|
IDisposable next = |
| 355 |
|
(IDisposable)iter.next();<br> |
| 356 |
|
<br> |
| 357 |
|
next.dispose();<br> |
| 358 |
|
}<br> |
| 359 |
|
}<br> |
| 360 |
|
}<br> |
| 361 |
|
<br> |
| 362 |
|
</code><code>/**<br> |
| 363 |
|
* Base class for all views.<br> |
| 364 |
|
*/<br> |
| 365 |
|
public abstract class View {<br> |
| 366 |
|
private IAdaptable mySite;<br> |
| 367 |
|
<br> |
| 368 |
|
public View(IAdaptable viewSite) {<br> |
| 369 |
|
mySite = viewSite;<br> |
| 370 |
|
}<br> |
| 371 |
|
<br> |
| 372 |
|
public IAdaptable getSite() {<br> |
| 373 |
|
return mySite;<br> |
| 374 |
|
}<br> |
| 375 |
|
<br> |
| 376 |
|
public abstract String getTitle();<br> |
| 377 |
|
<br> |
| 378 |
|
public void dispose() {};<br> |
| 379 |
|
}</code><br> |
| 380 |
|
</div> |
| 381 |
|
<br> |
| 382 |
|
Notice that this type of adapter is slightly different from most other |
| 383 |
|
adapters in Eclipse since it keeps some state and need to be notified |
| 384 |
|
when the Site is disposed. <br> |
| 385 |
|
<br> |
| 386 |
|
A particular view would look like this:<br> |
| 387 |
|
<br> |
| 388 |
|
<div style="margin-left: 40px;"><code>/**<br> |
| 389 |
|
* My implementation of a view<br> |
| 390 |
|
*/<br> |
| 391 |
|
public class MyView extends View {<br> |
| 392 |
|
IImageAllocator allocator;<br> |
| 393 |
|
<br> |
| 394 |
|
public MyView(IAdaptable viewSite) {<br> |
| 395 |
|
allocator = |
| 396 |
|
(IImageAllocator)viewSite.getAdapter(IImageAllocator.class);<br> |
| 397 |
|
<br> |
| 398 |
|
if (allocator == null) {<br> |
| 399 |
|
throw new Exception("I |
| 400 |
|
can't exist without images!");<br> |
| 401 |
|
}<br> |
| 402 |
|
}<br> |
| 403 |
|
<br> |
| 404 |
|
//...<br> |
| 405 |
|
}<br> |
| 406 |
|
<br> |
| 407 |
|
</code></div> |
| 408 |
|
Most views will contain similar code in their constructor that requests |
| 409 |
|
a set of adapters from their site and check that they aren't null. We |
| 410 |
|
can add some syntactic sugar to remove this repetition. Rather than |
| 411 |
|
having the view explicitly request every adapter it needs, it can take |
| 412 |
|
them as arguments to its constructor and the factory that creates the |
| 413 |
|
view can use reflection to ensure that it gets all the adapters it |
| 414 |
|
needs. Using this pattern, the same view would look like this:<br> |
| 415 |
|
<br> |
| 416 |
|
<div style="margin-left: 40px;"><code>/**</code><br> |
| 417 |
|
<code> * My implementation of a view</code><br> |
| 418 |
|
<code> */</code><br> |
| 419 |
|
<code>public class MyView extends View {</code><br> |
| 420 |
|
<code> IImageAllocator allocator;</code><br> |
| 421 |
|
<code></code><br> |
| 422 |
|
<code> public MyView(IImageAllocator imageAllocator) {<br> |
| 423 |
|
allocator = imageAllocator;<br> |
| 424 |
|
</code><code></code><code> }</code><br> |
| 425 |
|
<code></code><br> |
| 426 |
|
<code> //...</code><br> |
| 427 |
|
<code>}<br> |
| 428 |
|
<br> |
| 429 |
|
</code></div> |
| 430 |
|
Since the entire Site API would be provided by adapters, the Site class |
| 431 |
|
could be reduced to this:<br> |
| 432 |
|
<br> |
| 433 |
|
<div style="margin-left: 40px;"><code>/**</code><br> |
| 434 |
|
<code> * My implementation of a view</code><br> |
| 435 |
|
<code> */</code><br> |
| 436 |
|
<code>public abstract class Site implements IAdaptable {<br> |
| 437 |
|
public abstract Object getAdapter(Class adapter);<br> |
| 438 |
|
public abstract void dispose();<br> |
| 439 |
|
</code><code></code><code>}</code><br> |
| 440 |
|
</div> |
| 441 |
|
<br> |
| 442 |
|
In the component framework, this simplified Site interface is called |
| 443 |
|
IContainer. We now have a highly extensible Site interface, however the |
| 444 |
|
same versioning problems apply to the view as well. The parent of the |
| 445 |
|
view may want to access methods on the View, but we don't want to be |
| 446 |
|
continually adding things to the View base class. For this reason, we |
| 447 |
|
communicate with the view through adapters as well.<br> |
| 448 |
|
<br> |
| 449 |
|
This is the core pattern behind the component framework. It consists of:<br> |
| 450 |
|
<ol> |
| 451 |
|
<li>An extension point that allows 3rd party plugins to contribute |
| 452 |
|
interfaces to components (views and their sites)<br> |
| 453 |
|
</li> |
| 454 |
|
<li>A factory that allows components to be created through |
| 455 |
|
constructor injection</li> |
| 456 |
|
<li>A container interface that manages the lifecycle of components |
| 457 |
|
and their adapters </li> |
| 458 |
|
</ol> |
| 459 |
|
<div style="margin-left: 40px;"></div> |
| 460 |
|
<h2><a class="mozTocH2" name="mozTocId340323"></a>1.2 Requirements<br> |
| 461 |
|
</h2> |
| 462 |
Primary goals:<br> |
Primary goals:<br> |
| 463 |
<ul> |
<ul> |
| 464 |
<li>Robustness / leak proofing</li> |
<li>Robustness / leak proofing</li> |
| 469 |
</li> |
</li> |
| 470 |
<li>Ease of use</li> |
<li>Ease of use</li> |
| 471 |
</ul> |
</ul> |
| 472 |
<h2><a class="mozTocH2" name="mozTocId29093"></a>1.1 Robustness / leak |
<h3><a class="mozTocH2" name="mozTocId29093"></a>1.2.1 Robustness / |
| 473 |
|
leak |
| 474 |
proofing<br> |
proofing<br> |
| 475 |
</h2> |
</h3> |
| 476 |
Much of the Eclipse API is currently accessed through singleton |
Much of the Eclipse API is currently accessed through singleton |
| 477 |
objects. This makes it easy for a view or editor to leak listeners, |
objects. This makes it easy for a view or editor to leak listeners, |
| 478 |
fail to clean up reference counts, leak OS resources, etc. since there |
fail to clean up reference counts, leak OS resources, etc. since there |
| 479 |
is no way of tracking which resources were allocated by a particular |
is no way of tracking which resources were allocated by a particular |
| 480 |
view. This problem would be reduced if views and editors were more like |
view. This problem would be reduced if views and editors were more like |
| 481 |
mini-applications. The view or editor would access the rest of the |
mini-applications. The view or editor would access the rest of the |
| 482 |
world through a set of local services. When the view or editor is |
world through a set of local interfaces. When the view or editor is |
| 483 |
destroyed so would all of the services allocated for it. This gives |
destroyed, all the interfaces would be notified giving them a chance to |
| 484 |
each service a chance to clean up after itself. <br> |
clean up any leaked resources.<br> |
| 485 |
<br> |
<br> |
| 486 |
For example, instead of reaching into a global |
For example, instead of reaching into a global |
| 487 |
preference store, a view or editor could access all preferences through |
preference store, a view or editor could access all preferences through |
| 488 |
a local preference |
a local preference adapter. A unique instance of the local preference |
| 489 |
service. A unique instance of the local preference service would be |
adapter would be |
| 490 |
created for each view, and would be disposed with the view. When the |
created for each view, and would be disposed with the view. When the |
| 491 |
preference service is destroyed it would clear its listener list, |
preference adapter is destroyed it would clear its listener list, |
| 492 |
ensuring that the view will not leak any global listeners. This example |
ensuring that the view will not leak any global listeners. This example |
| 493 |
shows what we mean by a component. Essentially, a |
shows what we mean by a component. Essentially, a |
| 494 |
component is an object that communicates with the rest of the |
component is an object that communicates with the rest of the |
| 495 |
application through a set of interfaces given to it in its constructor.<br> |
application through a set of interfaces given to it in its constructor.<br> |
| 496 |
<span style="font-weight: bold;"></span> |
<span style="font-weight: bold;"></span> |
| 497 |
<h2><a class="mozTocH2" name="mozTocId223982"></a>1.2 Nesting of |
<h3><a class="mozTocH2" name="mozTocId223982"></a>1.2.2 Nesting of |
| 498 |
components</h2> |
components</h3> |
| 499 |
There is demand for the ability to embed views and editors inside one |
There is demand for the ability to embed views and editors inside one |
| 500 |
another. Some examples:<br> |
another. Some examples:<br> |
| 501 |
<ul> |
<ul> |
| 510 |
</li> |
</li> |
| 511 |
</ul> |
</ul> |
| 512 |
Many downstream plugins have solved these problems by creating their |
Many downstream plugins have solved these problems by creating their |
| 513 |
own frameworks for reusable UI components. Unfortunately, only works |
own frameworks for reusable UI components. Unfortunately, this only |
| 514 |
|
works |
| 515 |
for specific views and editors, does not encourage interoperability |
for specific views and editors, does not encourage interoperability |
| 516 |
between plugins that have adopted different frameworks, and requires a |
between plugins that have adopted different frameworks, and requires a |
| 517 |
lot of work. The goal here is to adopt a framework in the workbench |
lot of work. The goal here is to adopt a framework in the workbench |
| 518 |
itself that allows all editors, views, and other workbench objects to |
itself that allows all editors, views, and other workbench objects to |
| 519 |
be easily nested.<br> |
be easily nested.<br> |
| 520 |
<h2><a class="mozTocH2" name="mozTocId634024"></a>1.3 Creating parts |
<h3><a class="mozTocH2" name="mozTocId634024"></a>1.2.3 Creating parts |
| 521 |
outside the workbench</h2> |
outside the workbench</h3> |
| 522 |
It should be possible to instantiate views and editors outside the |
It should be possible to instantiate views and editors outside the |
| 523 |
workbench. Some examples:<br> |
workbench. Some examples:<br> |
| 524 |
<ul> |
<ul> |
| 528 |
but includes view-like pluggable parts |
but includes view-like pluggable parts |
| 529 |
that could also be used as views within Eclipse</li> |
that could also be used as views within Eclipse</li> |
| 530 |
</ul> |
</ul> |
| 531 |
<h2><a class="mozTocH2" name="mozTocId800379"></a>1.4 Scalability</h2> |
<h3><a class="mozTocH2" name="mozTocId800379"></a>1.2.4 Scalability</h3> |
| 532 |
The workbench currently offers a closed set of services to parts. This |
The workbench currently offers a closed interface to parts. This |
| 533 |
forces parts to reach to global objects whenever they need something |
forces parts to reach to global objects whenever they need something |
| 534 |
that isn't available from their site. It should be possible for any |
that isn't available from their site. It should be possible for any |
| 535 |
plugin to contribute to the set of local API available to a part, and |
plugin to contribute to the set of local API available to a part, and |
| 536 |
it |
it |
| 537 |
should be possible to instantiate a part even if its parent doesn't |
should be possible to instantiate a part even if its parent doesn't |
| 538 |
know about all of a part's dependencies.<br> |
know about all of a part's dependencies.<br> |
| 539 |
<h2><a class="mozTocH2" name="mozTocId866479"></a>1.5 Ease of use<br> |
<h3><a class="mozTocH2" name="mozTocId866479"></a>1.2.5 Ease of use<br> |
| 540 |
</h2> |
</h3> |
| 541 |
Views and editors currently have a complicated lifecycle that must be |
Views and editors currently have a complicated lifecycle that must be |
| 542 |
managed by the workbench. This complexity should not be exposed to |
managed by the workbench. This complexity should not be exposed to |
| 543 |
client code. <br> |
client code. <br> |
| 557 |
<h1><a class="mozTocH1" name="mozTocId416167"></a>2.0 Component |
<h1><a class="mozTocH1" name="mozTocId416167"></a>2.0 Component |
| 558 |
Framework<br> |
Framework<br> |
| 559 |
</h1> |
</h1> |
| 560 |
Components are pluggable objects that are build using constructor |
First, some terminology. The pluggable objects that clients write are |
| 561 |
|
called "components". For example, the class that contains the |
| 562 |
|
implementation of a view itself would be called a component. A |
| 563 |
|
component exists inside an IContainer. In the case of editors and |
| 564 |
|
views, IContainer replaces the existing IWorkbenchSite. Unlike |
| 565 |
|
IWorkbenchSite, the component never needs to directly access the |
| 566 |
|
IContainer since all of its useful interface is provided through |
| 567 |
|
adapters. Instead, the component supplies a constructor that takes all |
| 568 |
|
the interfaces it needs, and it communicates with the outside world |
| 569 |
|
through these interfaces.<br> |
| 570 |
|
<br> |
| 571 |
|
Components are built using constructor |
| 572 |
injection. Constructor injection means that the framework looks at the |
injection. Constructor injection means that the framework looks at the |
| 573 |
object's constructor to determine what it needs to do to build that |
object's constructor to determine what it needs to do to build that |
| 574 |
object.<br> |
object.<br> |
| 599 |
like this:<br> |
like this:<br> |
| 600 |
<br> |
<br> |
| 601 |
<div style="margin-left: 40px;"><code>/**</code><br> |
<div style="margin-left: 40px;"><code>/**</code><br> |
| 602 |
<code> * "Hello world" view using the service framework</code><br> |
<code> * "Hello world" view using the component framework</code><br> |
| 603 |
<code> */</code><br> |
<code> */</code><br> |
| 604 |
<code>public class HelloWorldView {</code><br> |
<code>public class HelloWorldView {</code><br> |
| 605 |
<code> public HelloWorldView(Composite parent) {</code><br> |
<code> public HelloWorldView(Composite parent) {</code><br> |
| 612 |
<code>}</code><br> |
<code>}</code><br> |
| 613 |
<code></code></div> |
<code></code></div> |
| 614 |
<code><br> |
<code><br> |
| 615 |
</code>The HelloWorldView component depends on one service: a Composite |
</code>The HelloWorldView component depends on one other object: a |
| 616 |
|
Composite |
| 617 |
created for it by whoever instantiated the view. Compare this with the |
created for it by whoever instantiated the view. Compare this with the |
| 618 |
same view written using the existing API:<br> |
same view written using the existing API:<br> |
| 619 |
<br> |
<br> |
| 694 |
view that previously implemented the IViewInterface1 migrates to using |
view that previously implemented the IViewInterface1 migrates to using |
| 695 |
the newer IViewInterface2, its container will continue to work as long |
the newer IViewInterface2, its container will continue to work as long |
| 696 |
as someone has provided an adapter between the two versions of |
as someone has provided an adapter between the two versions of |
| 697 |
IViewInterface. The getAdapter() method on IComponent searches for |
IViewInterface. The getAdapter() method on IContainer searches for |
| 698 |
adapters in the following order:<br> |
adapters in the following order:<br> |
| 699 |
<br> |
<br> |
| 700 |
1. If the component itself implements the adapter type, it returns the |
1. If the component itself implements the adapter type, it returns the |
| 771 |
caller MUST call IContainer.dispose() <br> |
caller MUST call IContainer.dispose() <br> |
| 772 |
* when it is done with the component. The |
* when it is done with the component. The |
| 773 |
factory does not need any prior<br> |
factory does not need any prior<br> |
| 774 |
* knowledge of the component class be<br> |
* knowledge of the component class.<br> |
| 775 |
* <br> |
* <br> |
| 776 |
* @param componentImplementation concrete |
* @param componentImplementation concrete |
| 777 |
class to be instantiated by the factory. The class<br> |
class to be instantiated by the factory. The class<br> |
| 782 |
references other component interfaces known to this factory).<br> |
references other component interfaces known to this factory).<br> |
| 783 |
* @return a newly constructed |
* @return a newly constructed |
| 784 |
<code>IContainer</code> instance<br> |
<code>IContainer</code> instance<br> |
| 785 |
* @throws MissingDependencyException if the |
* @throws CoreException if unable to create |
| 786 |
requested component depends on another component that<br> |
the component<br> |
|
|
|
|
* cannot be constructed |
|
|
by this factory<br> |
|
|
* @throws CoreException if there is a more |
|
|
permanent problem with using the given class as <br> |
|
|
|
|
|
* a component <br> |
|
|
* @since 3.1<br> |
|
| 787 |
*/<br> |
*/<br> |
| 788 |
public IContainer createContainer(Class |
public IContainer createContainer(Class |
| 789 |
componentImplementation) throws MissingDependencyException, |
componentImplementation) throws CoreException;<br> |
|
CoreException;<br> |
|
| 790 |
<br> |
<br> |
| 791 |
/**<br> |
/**<br> |
| 792 |
* Creates a specialization of this factory. By |
* Creates a specialization of this factory. By |
| 802 |
delegate all of its behavior to the receiver.<br> |
delegate all of its behavior to the receiver.<br> |
| 803 |
* Changes in the receiver will affect the |
* Changes in the receiver will affect the |
| 804 |
derived factory.<br> |
derived factory.<br> |
|
* @since 3.1<br> |
|
| 805 |
*/<br> |
*/<br> |
| 806 |
public IMutableContainerFactory |
public IMutableContainerFactory |
| 807 |
createDerivedFactory();<br> |
createDerivedFactory();<br> |
| 808 |
}</code><code></code><br> |
}</code><code></code><br> |
| 809 |
<code></code></div> |
<code></code></div> |
| 810 |
<code></code><br> |
<code></code><br> |
|
Notice that createComponent throws two types of exception. A |
|
|
CoreException indicates a problem with the component itself, and a |
|
|
MissingDependencyException indicates that some other component or |
|
|
adapter could not be found. This can help locate the cause of problems, |
|
|
and a robust extension point may want to disable components that throw |
|
|
CoreExceptions.<br> |
|
|
<br> |
|
| 811 |
All arguments to a component's constructor are provided by its factory. |
All arguments to a component's constructor are provided by its factory. |
| 812 |
Different |
Different |
| 813 |
factories know how to create different types of components or will |
factories know how to create different types of components or will |
| 815 |
different implementations for the same components. All factories are |
different implementations for the same components. All factories are |
| 816 |
derived from the root factory, which is returned by |
derived from the root factory, which is returned by |
| 817 |
Components.getFactory(). A plugin can create derived factories to |
Components.getFactory(). A plugin can create derived factories to |
| 818 |
supply services to one specific extension point. It is also possible to |
supply alternative adapter implementations to the components it creates.<br> |
| 819 |
create a derived factory in order to pass information to the |
<br> |
| 820 |
constructor of one specific object, as we will do in this example. In |
In |
| 821 |
our case, we will create a container factory to pass a specific |
our case, we will create a container factory to pass a specific |
| 822 |
Composite into the constructor of HelloWorldView. The code looks like |
Composite into the constructor of HelloWorldView. The code looks like |
| 823 |
this:<br> |
this:<br> |
| 837 |
<code>IMutableContainerFactory derivedFactory = |
<code>IMutableContainerFactory derivedFactory = |
| 838 |
viewFactory.createDerivedFactory();</code><br> |
viewFactory.createDerivedFactory();</code><br> |
| 839 |
<code></code><br> |
<code></code><br> |
| 840 |
<code>// Add the view's composite as a service instance</code><br> |
<code>// Add the view's composite to the factory so that it can be seen |
| 841 |
<code>derivedFactory.addComponentInstance(viewComposite);</code><br> |
by the view constructor<br> |
| 842 |
|
</code><code>derivedFactory.addComponentInstance(viewComposite);</code><br> |
| 843 |
<code></code><br> |
<code></code><br> |
| 844 |
<code>// Add the view's plugin bundle as a service instance (not |
<code>// Add the view's plugin bundle to the factory (not |
| 845 |
required in this example, but this</code><br> |
required in this example, but this</code><br> |
| 846 |
<code>// is recommended practise for any component created from an |
<code>// is recommended practise for any component created from an |
| 847 |
extension point).</code><br> |
extension point).</code><br> |
| 866 |
1. Even if HelloWorldView didn't require a Composite, we would still |
1. Even if HelloWorldView didn't require a Composite, we would still |
| 867 |
have created one (which is wasteful).<br> |
have created one (which is wasteful).<br> |
| 868 |
2. We need to manually dispose the view's composite after we're done |
2. We need to manually dispose the view's composite after we're done |
| 869 |
with it. This defeats the point of IComponent.dispose(), which is |
with it. This defeats the point of IContainer.dispose(), which is |
| 870 |
supposed to clean up all of the component's dependencies automatically.<br> |
supposed to clean up all of the component's dependencies automatically.<br> |
| 871 |
<h2><a class="mozTocH2" name="mozTocId450231"></a>2.3 Creating |
<h2><a class="mozTocH2" name="mozTocId450231"></a>2.3 Creating |
| 872 |
dependent components on demand </h2> |
dependent components on demand </h2> |
| 875 |
a factory would look like this:<br> |
a factory would look like this:<br> |
| 876 |
<br> |
<br> |
| 877 |
<div style="margin-left: 40px;"><code>/**</code><br> |
<div style="margin-left: 40px;"><code>/**</code><br> |
| 878 |
<code> * ServiceAdapter for creating and managing SWT Composites |
<code> * ComponentAdapter for creating and managing SWT Composites.</code><br> |
|
as services.</code><br> |
|
| 879 |
<code> */</code><br> |
<code> */</code><br> |
| 880 |
<code>public class CompositeFactory extends ComponentAdapter {</code><br> |
<code>public class CompositeFactory extends ComponentAdapter {</code><br> |
| 881 |
<code></code><br> |
<code></code><br> |
| 891 |
<code> }</code><br> |
<code> }</code><br> |
| 892 |
<code> </code><br> |
<code> </code><br> |
| 893 |
<code> protected Object create(IAdaptable |
<code> protected Object create(IAdaptable |
| 894 |
availableServices) throws CoreException {</code><br> |
availableAdapters) throws CoreException {</code><br> |
| 895 |
<code> // Create a new Composite |
<code> // Create a new Composite</code><code></code><br> |
|
which will be used as a service.</code><br> |
|
|
<code> // If we needed any |
|
|
additional</code><br> |
|
| 896 |
<code> Composite newChild = |
<code> Composite newChild = |
| 897 |
new Composite(parent, SWT.NONE);</code><br> |
new Composite(parent, SWT.NONE);</code><br> |
| 898 |
<code> newChild.setLayout(new |
<code> newChild.setLayout(new |
| 900 |
<code> return newChild;</code><br> |
<code> return newChild;</code><br> |
| 901 |
<code> }</code><br> |
<code> }</code><br> |
| 902 |
<code></code><br> |
<code></code><br> |
| 903 |
<code> protected void dispose(Object service) {</code><br> |
<code> protected void dispose(Object toDispose) {</code><br> |
| 904 |
<code> |
<code> |
| 905 |
((Composite)service).dispose();</code><br> |
((Composite)toDispose).dispose();</code><br> |
| 906 |
<code> }</code><br> |
<code> }</code><br> |
| 907 |
<code></code><br> |
<code></code><br> |
| 908 |
<code> public String getInterfaceName() {</code><br> |
<code> public String getInterfaceName() {</code><br> |
| 909 |
<code> // Return the fully |
<code> // Return the fully |
| 910 |
qualified class name of the Composite class. The framework will call</code><br> |
qualified class name of the Composite class. The framework will call</code><br> |
| 911 |
<code> // this method to determine |
<code> // this method to determine |
| 912 |
what type of service will be constructed by this factory.</code><br> |
what type of interface will be implemented by the objects <br> |
| 913 |
|
// constructed by this factory.</code><br> |
| 914 |
<code> return |
<code> return |
| 915 |
Composite.class.getName();</code><br> |
Composite.class.getName();</code><br> |
| 916 |
<code> }</code><br> |
<code> }</code><br> |
| 928 |
<code>IMutableContainerFactory derivedFactory = |
<code>IMutableContainerFactory derivedFactory = |
| 929 |
viewFactory.createDerivedFactory();</code><br> |
viewFactory.createDerivedFactory();</code><br> |
| 930 |
<code></code><br> |
<code></code><br> |
| 931 |
<code>// Add the view's composite as a service instance</code><br> |
<code>// Add a factory that can create the view's composite</code><br> |
| 932 |
<code>derivedFactory.addComponentFactory(new |
<code>derivedFactory.addComponentFactory(new |
| 933 |
CompositeFactory(parentComposite));</code><br> |
CompositeFactory(parentComposite));</code><br> |
| 934 |
<code></code><br> |
<code></code><br> |
| 935 |
<code>// Add the view's plugin bundle as a service instance (not |
<code>// Add the view's plugin bundle to the factory (not |
| 936 |
required in this example, but this</code><br> |
required in this example, but this</code><br> |
| 937 |
<code>// is recommended practise for any component created from an |
<code>// is recommended practise for any component created from an |
| 938 |
extension point).</code><br> |
extension point).</code><br> |
| 955 |
call to view.dispose().<br> |
call to view.dispose().<br> |
| 956 |
<br> |
<br> |
| 957 |
<code></code> |
<code></code> |
| 958 |
<h2><a class="mozTocH2" name="mozTocId928619"></a>2.4 Declaring Global |
<h2><a class="mozTocH2" name="mozTocId928619"></a>2.4 Declaring |
| 959 |
Services<br> |
Component Interfaces</h2> |
| 960 |
</h2> |
The types that a component receives in its constructor are called |
| 961 |
Services are a type of component that can be used by other components. |
component interfaces. Component interfaces are registered through the <span |
| 962 |
Services are registered through the <span style="font-style: italic;">org.eclipse.ui.component.service |
style="font-style: italic;">org.eclipse.core.component.interface</span> |
| 963 |
</span>extension |
extension point, and each has a default implementation. When a |
| 964 |
point. Services are global in the sense that they are created by |
component is |
| 965 |
factories |
created, its parent may provide an implementation of any service |
| 966 |
that are visible everywhere, however each instance of a services is |
it knows about. If the component requests an interface that isn't |
| 967 |
associated with a specific IContainer. Each service implements a |
provided explicitly by the parent, the default implementation is used.<br> |
|
service interface. Other components can use the service interface in |
|
|
their constructor. When they do so, a new instance of the service will |
|
|
be created for that component which will be managed by the same |
|
|
IContainer. <br> |
|
| 968 |
<br> |
<br> |
| 969 |
Each component supplies an implementation and an interface. Here is an |
Here is an |
| 970 |
example service interface:<br> |
example component interface:<br> |
| 971 |
<code><br> |
<code><br> |
| 972 |
</code> |
</code> |
| 973 |
<div style="margin-left: 40px;"><code>/**</code><br> |
<div style="margin-left: 40px;"><code>/**</code><br> |
| 974 |
<code> * Service interface: </code><br> |
<code> * Component interface: </code><br> |
| 975 |
<code> *</code><br> |
<code> *</code><br> |
| 976 |
<code> * Provides a context for reporting and logging exceptions.</code><br> |
<code> * Provides a context for reporting and logging exceptions.</code><br> |
| 977 |
<code> */</code><br> |
<code> */</code><br> |
| 1005 |
<code></code></div> |
<code></code></div> |
| 1006 |
<code><br> |
<code><br> |
| 1007 |
<br> |
<br> |
| 1008 |
</code>Here is the associated service implementation:<br> |
</code>Here is the associated default implementation:<br> |
| 1009 |
<code><br> |
<code><br> |
| 1010 |
</code> |
</code> |
| 1011 |
<div style="margin-left: 40px;"><code>/**</code><br> |
<div style="margin-left: 40px;"><code>/**</code><br> |
| 1012 |
<code> * Service implementation:</code><br> |
<code> * Default implementation of the IErrorContext interface:</code><br> |
| 1013 |
<code> *</code><br> |
<code> *</code><br> |
| 1014 |
<code> * Creates and logs errors in the context of a plugin bundle</code><br> |
<code> * Creates and logs errors in the context of a plugin bundle</code><br> |
| 1015 |
<code> */</code><br> |
<code> */</code><br> |
| 1016 |
<code>public class ErrorContext implements IErrorContext {</code><br> |
<code>public class ErrorContext implements IErrorContext {</code><br> |
| 1017 |
<code> private Bundle pluginBundle;</code><br> |
<code> private Bundle pluginBundle;</code><br> |
| 1018 |
<code></code><br> |
<code></code><br> |
| 1019 |
<code> public ExceptionLoggingService(Bundle |
<code> public ErrorContext(Bundle |
| 1020 |
pluginBundle) {</code><br> |
pluginBundle) {</code><br> |
| 1021 |
<code> this.pluginBundle = |
<code> this.pluginBundle = |
| 1022 |
pluginBundle;</code><br> |
pluginBundle;</code><br> |
| 1054 |
Finally, here is the extension markup:<br> |
Finally, here is the extension markup:<br> |
| 1055 |
<br> |
<br> |
| 1056 |
<div style="margin-left: 40px;"><code><extension |
<div style="margin-left: 40px;"><code><extension |
| 1057 |
point="org.eclipse.ui.component.service"></code><br> |
point="org.eclipse.core.component.interface"></code><br> |
| 1058 |
<code> <service |
<code> <interface |
| 1059 |
</code><br> |
</code><br> |
| 1060 |
<code> |
<code> |
| 1061 |
class="org.eclipse.ui.workbench.ErrorContext"</code><br> |
class="org.eclipse.ui.workbench.ErrorContext"</code><br> |
| 1062 |
<code> </code><code>interface="</code><code>org.eclipse.ui.workbench.IErrorContext</code><code>"</code><code>></code><br> |
<code> </code><code>interface="</code><code>org.eclipse.ui.workbench.IErrorContext</code><code>"<br> |
| 1063 |
<code> </service></code><br> |
childadapter="false"<br> |
| 1064 |
|
</code><code> scope="plugin"></code><br> |
| 1065 |
|
<code> </interface></code><br> |
| 1066 |
<code></extension></code><br> |
<code></extension></code><br> |
| 1067 |
</div> |
</div> |
| 1068 |
<br> |
<br> |
| 1075 |
the status messages constructed by the view will be associated with the |
the status messages constructed by the view will be associated with the |
| 1076 |
view's own plugin - not the plugin that defined the ErrorContext |
view's own plugin - not the plugin that defined the ErrorContext |
| 1077 |
service.<br> |
service.<br> |
| 1078 |
<h2><a class="mozTocH2" name="mozTocId749133"></a>2.5 Using services</h2> |
<br> |
| 1079 |
This example shows how a component can use a service.<br> |
The <span style="font-style: italic;">scope</span> attribute is a path |
| 1080 |
|
indicating how much context is needed to create the service. The <span |
| 1081 |
|
style="font-style: italic;">plugin </span>scope indicates that this |
| 1082 |
|
service is associated with a plugin, which is why it is allowed to take |
| 1083 |
|
a Bundle in its constructor. More on scopes later.<br> |
| 1084 |
|
<br> |
| 1085 |
|
The <span style="font-style: italic;">childadapter="false" </span>tag |
| 1086 |
|
is optional. The default value, false, indicates that a component can |
| 1087 |
|
take the interface in its constructor and/or supply an alternative |
| 1088 |
|
implementation to its children. If <span style="font-style: italic;">childadapter="true"</span> |
| 1089 |
|
were specified, the component would be allowed to implement the |
| 1090 |
|
interface or request it from its children. Essentially, this determines |
| 1091 |
|
if the interface is intended for top-down or bottom-up communication |
| 1092 |
|
between a component and its parent.<br> |
| 1093 |
|
<br> |
| 1094 |
|
Plugins are not allowed to declare services using interfaces defined in |
| 1095 |
|
another plugin. This prevents two plugins from defining a service using |
| 1096 |
|
the same interface, and ensures that circular dependencies can only |
| 1097 |
|
occur within the same plugin.<br> |
| 1098 |
|
<h2><a class="mozTocH2" name="mozTocId749133"></a>2.5 Using Component |
| 1099 |
|
Interfaces<br> |
| 1100 |
|
</h2> |
| 1101 |
|
This example shows how a component can use an interface supplied by its |
| 1102 |
|
parent.<br> |
| 1103 |
<br> |
<br> |
| 1104 |
<div style="margin-left: 40px;"><code>public class MyView {</code><br> |
<div style="margin-left: 40px;"><code>public class MyView {</code><br> |
| 1105 |
<code> private IErrorContext errorContext;</code><br> |
<code> private IErrorContext errorContext;</code><br> |
| 1136 |
} catch (Exception e) {</code><br> |
} catch (Exception e) {</code><br> |
| 1137 |
<code> |
<code> |
| 1138 |
|
|
| 1139 |
// Log the NPE using the error context service</code><br> |
// Log the NPE using the error context</code><br> |
| 1140 |
<code> |
<code> |
| 1141 |
errorContext.log(e);</code><br> |
errorContext.log(e);</code><br> |
| 1142 |
<code> |
<code> |
| 1149 |
<code><br> |
<code><br> |
| 1150 |
</code>This view creates a button which, when pressed, will throw a NPE |
</code>This view creates a button which, when pressed, will throw a NPE |
| 1151 |
and log it. The status message will be constructed and logged using the |
and log it. The status message will be constructed and logged using the |
| 1152 |
IErrorContext service we defined above.<br> |
IErrorContext interface we defined above. The default implementation of |
| 1153 |
|
the interface is associated with a |
| 1154 |
|
unique component instance, so if we were to create two instances of |
| 1155 |
|
MyView we would also end up with two instances of ErrorContext. <br> |
| 1156 |
|
<br> |
| 1157 |
|
There |
| 1158 |
|
is never any ambiguity about which implementation of IErrorContext to |
| 1159 |
|
use. If the parent of MyView explicitly supplies an IErrorContext |
| 1160 |
|
service, that implementation is used. Otherwise, the unique default |
| 1161 |
|
implementation is used. There can never be two global implementations.<br> |
| 1162 |
<br> |
<br> |
| 1163 |
<h2><a class="mozTocH2" name="mozTocId705695"></a>2.6 Lifecycle</h2> |
<h2><a class="mozTocH2" name="mozTocId705695"></a>2.6 Lifecycle</h2> |
| 1164 |
Many components need to do explicit cleanup. Components |
Many components need to do explicit cleanup. Components |
| 1238 |
<code> /**</code><br> |
<code> /**</code><br> |
| 1239 |
<code> * This method will automatically be |
<code> * This method will automatically be |
| 1240 |
called |
called |
| 1241 |
when the component that uses this service is disposed.</code><br> |
when the component that uses this adapter is disposed.</code><br> |
| 1242 |
<code> * It should clean up anything that has |
<code> * It should clean up anything that has |
| 1243 |
been |
been |
| 1244 |
allocated by the service.</code><br> |
allocated by the service.</code><br> |
| 1259 |
<code></code></div> |
<code></code></div> |
| 1260 |
<code></code><br> |
<code></code><br> |
| 1261 |
Similarly, components may implement the IDisposable interface. A |
Similarly, components may implement the IDisposable interface. A |
| 1262 |
component that implements IDisposable will be disposed before any of |
component that implements IDisposable will be disposed before the |
| 1263 |
its services, as shown by the following example:<br> |
objects it depends on, as shown by the following example:<br> |
| 1264 |
<br> |
<br> |
| 1265 |
<div style="margin-left: 40px;"><code>public LifecycleService |
<div style="margin-left: 40px;"><code>public LifecycleService |
| 1266 |
implements IDisposable {</code><br> |
implements IDisposable {</code><br> |
| 1291 |
<code>}</code><br> |
<code>}</code><br> |
| 1292 |
<code></code><br> |
<code></code><br> |
| 1293 |
</div> |
</div> |
| 1294 |
Finally, we could execute the following code to trace when the service |
Finally, we could execute the following code to trace when the |
| 1295 |
is created and destroyed:<br> |
LifecycleService is created and destroyed:<br> |
| 1296 |
<div style="margin-left: 40px;"><br> |
<div style="margin-left: 40px;"><br> |
| 1297 |
IMutableContainerFactory factory = |
IMutableContainerFactory factory = |
| 1298 |
Components.getFactory().createDerivedFactory();<br> |
Components.getFactory().createDerivedFactory();<br> |
| 1332 |
LifecycleService destroyed<br> |
LifecycleService destroyed<br> |
| 1333 |
<br> |
<br> |
| 1334 |
</div> |
</div> |
| 1335 |
<h2><a class="mozTocH2" name="mozTocId543223"></a>2.7 Dynamic Services</h2> |
<h2><a class="mozTocH2" name="mozTocId543223"></a>2.7 Dynamic Interfaces<br> |
| 1336 |
Global service factories are dynamic in the sense that they come and go |
</h2> |
| 1337 |
as plugins are installed or uninstalled. If a plugin providing a |
Component interfaces are dynamic in the sense that they may be |
| 1338 |
service is uninstalled, a new implementation is selected from a |
registered or unregistered as their plugins are installed or |
| 1339 |
different plugin. If no other plugin provides that service, the service |
uninstalled. If a plugin providing component interface is uninstalled, |
| 1340 |
becomes unavailable and it will not be possible to construct components |
that interface will become unavailable and it will no longer be |
| 1341 |
that use it.<br> |
possible to construct objects that depend on the interface.<br> |
| 1342 |
<br> |
<br> |
| 1343 |
Service instances themselves are not dynamic. Once a service is |
The objects instances themselves are not dynamic. Once an adapter is |
| 1344 |
created, it will exist for as long as the component it was created for. |
created to supply an interface, it will exist for as long as the |
| 1345 |
Even if the a plugin stops providing a service, all instances of that |
component it was created for. |
| 1346 |
service will continue to exist until disposed. All services used by a |
Even if the a plugin stops providing an interface, all instances of |
| 1347 |
|
that |
| 1348 |
|
interface will continue to exist until disposed. All interfaces used by |
| 1349 |
|
a |
| 1350 |
component will be created before that component, so components do not |
component will be created before that component, so components do not |
| 1351 |
need to query for the existence of services or to wait for services |
need to query for the existence of services or to wait for services |
| 1352 |
that will be created after-the-fact. <br> |
that will be created after-the-fact. <br> |
| 1353 |
<br> |
<h2><a class="mozTocH2" name="mozTocId886834"></a>2.8 Optional Interface<br> |
|
Plugins that need more advanced dynamic support should use OSGI |
|
|
services. The component framework is not intended as a replacement for |
|
|
OSGI, and there is no point in reimplmenting things that OSGI already |
|
|
does well.<br> |
|
|
<h2><a class="mozTocH2" name="mozTocId886834"></a>2.8 Optional Services<br> |
|
| 1354 |
</h2> |
</h2> |
| 1355 |
Sometimes a component does not require a service but can make use of it |
Sometimes a component does not require an interface but can make use of |
| 1356 |
service if it exists. This should usually be handled by explicitly |
it if it exists. This is normally not necessary for any interface |
| 1357 |
creating an empty global implementation of the service, but sometimes |
registered through the <code>org.eclipse.core.component.interface</code> |
| 1358 |
it is more efficient to have the component explicitly check if the |
extension point since the default implementation will guarantee that |
| 1359 |
service exists. This can be done by taking an argument of type |
the interface always exists even if the parent context doesn't know |
| 1360 |
|
about it. However, this situation can occur if a parent and child are |
| 1361 |
|
communicating with an interface that wasn't originally intended for use |
| 1362 |
|
as a component interface, or if the child requires a variable set of |
| 1363 |
|
interfaces.<br> |
| 1364 |
|
<br> |
| 1365 |
|
Note: this pattern doesn't actually allow the component to be used in a |
| 1366 |
|
wider context, but it does allow the component to request interfaces |
| 1367 |
|
that aren't registered by the normal means.<br> |
| 1368 |
|
<br> |
| 1369 |
|
This can be done by taking an argument of type |
| 1370 |
IAdaptable, like this:<br> |
IAdaptable, like this:<br> |
| 1371 |
<br> |
<br> |
| 1372 |
<div style="margin-left: 40px;"><code>/**<br> |
<div style="margin-left: 40px;"><code>public interface INameService {<br> |
| 1373 |
|
public String getName();<br> |
| 1374 |
|
}<br> |
| 1375 |
|
<br> |
| 1376 |
|
<br> |
| 1377 |
|
/**<br> |
| 1378 |
* A component with no dependencies, but which can optionally |
* A component with no dependencies, but which can optionally |
| 1379 |
accept an IMemento for initialization.<br> |
accept an IMemento for initialization.<br> |
| 1380 |
*/<br> |
*/<br> |
| 1382 |
<br> |
<br> |
| 1383 |
String myName = "default name";<br> |
String myName = "default name";<br> |
| 1384 |
<br> |
<br> |
| 1385 |
public MyComponent(IAdaptable optionalServices) {<br> |
public MyComponent(IAdaptable optionalInterfaces) {<br> |
| 1386 |
<br> |
<br> |
| 1387 |
</code><code> // Check if an IMemento |
</code><code> // Check if an |
| 1388 |
|
INameService |
| 1389 |
service exists.</code><br> |
service exists.</code><br> |
| 1390 |
<code> IMemento memento = |
<code> INameService nameService = |
| 1391 |
(IMemento)optionalServices.getAdapter(IMemento.class);<br> |
(INameService)optionalInterfaces.getAdapter(INameService.class);<br> |
| 1392 |
<br> |
<br> |
| 1393 |
if (memento != null) {<br> |
if (memento != null) {<br> |
| 1394 |
String name = |
myName = |
| 1395 |
memento.getString("name");<br> |
nameService.getName();<br> |
|
if (name != null) {<br> |
|
|
myName = name;<br> |
|
|
}<br> |
|
| 1396 |
}<br> |
}<br> |
| 1397 |
<br> |
<br> |
| 1398 |
System.out.println("created component |
System.out.println("created component |
| 1405 |
<br> |
<br> |
| 1406 |
<div style="margin-left: 40px;"><code>// Create a memento with the name |
<div style="margin-left: 40px;"><code>// Create a memento with the name |
| 1407 |
"custom name"<br> |
"custom name"<br> |
| 1408 |
IMemento memento = XMLMemento.createWriteRoot("test");<br> |
INameService nameService = new INameService() {<br> |
| 1409 |
memento.putString("name", "custom name");<br> |
public String getName() {<br> |
| 1410 |
|
return "custom name";<br> |
| 1411 |
|
}<br> |
| 1412 |
|
}<br> |
| 1413 |
<br> |
<br> |
| 1414 |
// Create a factory which knows about our memento<br> |
// Create a factory which knows about our memento<br> |
| 1415 |
IMutableContainerFactory context = |
IMutableContainerFactory context = |
| 1416 |
Components.getFactory().createDerivedFactory();<br> |
Components.getFactory().createDerivedFactory();<br> |
| 1417 |
context.addComponentInstance(memento);<br> |
context.addComponentInstance(nameService);<br> |
| 1418 |
<br> |
<br> |
| 1419 |
// Use the factory to instantiate MyComponent<br> |
// Use the factory to instantiate MyComponent<br> |
| 1420 |
IContainer component = context.createContainer(MyComponent.class);<br> |
IContainer component = context.createContainer(MyComponent.class);<br> |
| 1422 |
component.dispose();</code><br> |
component.dispose();</code><br> |
| 1423 |
<br> |
<br> |
| 1424 |
</div> |
</div> |
| 1425 |
We can also create the component without the optional IMemento:<br> |
We can also create the component without the optional INameService:<br> |
| 1426 |
<br> |
<br> |
| 1427 |
<div style="margin-left: 40px;"><code>IContainer component = |
<div style="margin-left: 40px;"><code>IContainer component = |
| 1428 |
Components.getFactory().createContainer(MyComponent.class);<br> |
Components.getFactory().createContainer(MyComponent.class);<br> |
| 1430 |
component.dispose();</code><code></code><br> |
component.dispose();</code><code></code><br> |
| 1431 |
</div> |
</div> |
| 1432 |
<br> |
<br> |
|
WARNING: This pattern should be used with care since it adds special |
|
|
cases to the component code. It is mainly inteded for situations where |
|
|
a component requires an open-ended set of services or where it is not |
|
|
possible to offer a default implementation of a service.<br> |
|
| 1433 |
<br> |
<br> |
| 1434 |
<h2><a class="mozTocH2" name="mozTocId163729"></a>2.9 Multiplexing |
<span style="font-weight: bold;">WARNING: </span>This pattern should |
| 1435 |
services</h2> |
be used with care since it adds special |
| 1436 |
|
cases to the component code. It is mainly inteded for advanced |
| 1437 |
|
situations where a component needs to request an interface that isn't |
| 1438 |
|
normally visible in its scope.<br> |
| 1439 |
|
<br> |
| 1440 |
|
The preferred method of dealing with missing interfaces is to provide a |
| 1441 |
|
default implementation, like this:<br> |
| 1442 |
|
<br> |
| 1443 |
|
<div style="margin-left: 40px;"><code><extension |
| 1444 |
|
point="</code><code>org.eclipse.core.component.interface</code><code>"></code><br> |
| 1445 |
|
<code> <interface |
| 1446 |
|
</code><br> |
| 1447 |
|
<code> |
| 1448 |
|
class="org.eclipse.ui.DefaultNameService"</code><br> |
| 1449 |
|
<code> </code><code>interface="</code><code>org.eclipse.ui.INameService</code><code>"</code><code>></code><br> |
| 1450 |
|
<code> </interface></code><br> |
| 1451 |
|
<code></extension><br> |
| 1452 |
|
<br> |
| 1453 |
|
<br> |
| 1454 |
|
/**<br> |
| 1455 |
|
* Default implementation of INameService that will be used if the |
| 1456 |
|
parent doesn't explicitly provide one<br> |
| 1457 |
|
*/<br> |
| 1458 |
|
class NameService implements INameService {<br> |
| 1459 |
|
</code><code> public String getName() {<br> |
| 1460 |
|
return "default name";<br> |
| 1461 |
|
}<br> |
| 1462 |
|
</code><code>}<br> |
| 1463 |
|
<br> |
| 1464 |
|
</code><code>/**<br> |
| 1465 |
|
* A component with no dependencies, but which can optionally |
| 1466 |
|
accept an INameService for initialization.<br> |
| 1467 |
|
*/<br> |
| 1468 |
|
public class MyComponent {<br> |
| 1469 |
|
<br> |
| 1470 |
|
String myName;<br> |
| 1471 |
|
<br> |
| 1472 |
|
public MyComponent(INameService nameService) {<br> |
| 1473 |
|
myName = nameService.getName();<br> |
| 1474 |
|
</code><code></code><code><br> |
| 1475 |
|
System.out.println("created component |
| 1476 |
|
with name = " + myName);<br> |
| 1477 |
|
}<br> |
| 1478 |
|
}</code><code><br> |
| 1479 |
|
</code></div> |
| 1480 |
|
<br> |
| 1481 |
|
With this approach, it is still possible to create a MyComponent with |
| 1482 |
|
or without an INameService, but the special-case code for handling |
| 1483 |
|
missing interfaces is written once inside the default implementation |
| 1484 |
|
rather than many times inside each component that uses |
| 1485 |
|
the interface.<br> |
| 1486 |
|
<h2><a class="mozTocH2" name="mozTocId578639"></a>2.8 Component Scopes</h2> |
| 1487 |
|
Scopes are a way to determine what interfaces can be used in the |
| 1488 |
|
constructor of a component. At some point, a programmer is going to ask |
| 1489 |
|
"What interfaces am I allowed to pass into the constructor of my view?" |
| 1490 |
|
Ultimately, this could be determined by examining the dependencies |
| 1491 |
|
between each service, but it is not reasonable to expect a programmer |
| 1492 |
|
to have this level of knowledge of the dependencies between services.<br> |
| 1493 |
|
<br> |
| 1494 |
|
Scopes limit the dependencies between services in order to make this |
| 1495 |
|
question easier to answer. For example, views are allowed to use any |
| 1496 |
|
service in the "/plugin/part/view" scope. This makes it easy to write a |
| 1497 |
|
PDE extension which displays the list of interfaces available to a |
| 1498 |
|
views. <br> |
| 1499 |
|
<br> |
| 1500 |
|
The only difference between scopes is how much context the components |
| 1501 |
|
are allowed to expect. For example, components in the <span |
| 1502 |
|
style="font-style: italic;">plugin</span> scope will be given a plugin |
| 1503 |
|
Bundle and components in the <span style="font-style: italic;">plugin/part</span> |
| 1504 |
|
scope need to be associated with a particular SWT Composite. Components |
| 1505 |
|
may depend on services in the same scope or in a |
| 1506 |
|
more general scope. It is still possible for Components to reference |
| 1507 |
|
services in a more specific scope, but they must do so as an optional |
| 1508 |
|
interface (as described in section 2.7).<span |
| 1509 |
|
style="font-style: italic;"></span><br> |
| 1510 |
|
<br> |
| 1511 |
|
Eclipse defines the following standard scopes.<br> |
| 1512 |
|
<br> |
| 1513 |
|
<table style="width: 100%; text-align: left;" border="1" cellpadding="2" |
| 1514 |
|
cellspacing="2"> |
| 1515 |
|
<tbody> |
| 1516 |
|
<tr> |
| 1517 |
|
<td style="vertical-align: top;">Scope path<br> |
| 1518 |
|
</td> |
| 1519 |
|
<td style="vertical-align: top;">Required context<br> |
| 1520 |
|
</td> |
| 1521 |
|
<td style="vertical-align: top;">Description<br> |
| 1522 |
|
</td> |
| 1523 |
|
</tr> |
| 1524 |
|
<tr> |
| 1525 |
|
<td style="vertical-align: top;">/<br> |
| 1526 |
|
</td> |
| 1527 |
|
<td style="vertical-align: top;">None<br> |
| 1528 |
|
</td> |
| 1529 |
|
<td style="vertical-align: top;">Any service that omits the <span |
| 1530 |
|
style="font-style: italic;">scope</span> attribute automatically |
| 1531 |
|
belongs to the global scope. Services in the global scope can be used |
| 1532 |
|
by any other component, but may only depend on other global services. |
| 1533 |
|
Global services are not given any context from the application.<br> |
| 1534 |
|
</td> |
| 1535 |
|
</tr> |
| 1536 |
|
<tr> |
| 1537 |
|
<td style="vertical-align: top;">/plugin<br> |
| 1538 |
|
</td> |
| 1539 |
|
<td style="vertical-align: top;">Bundle<br> |
| 1540 |
|
</td> |
| 1541 |
|
<td style="vertical-align: top;">Components in the /plugin scope |
| 1542 |
|
are created in the context of a plugin bundle. All executable |
| 1543 |
|
extensions (any component created using an extension point) belong to |
| 1544 |
|
the plugin scope. Components in this scope can reference their own |
| 1545 |
|
plugin Bundle in their constructor. Services can reference the Bundle |
| 1546 |
|
associated with the component that requested them.<br> |
| 1547 |
|
</td> |
| 1548 |
|
</tr> |
| 1549 |
|
<tr> |
| 1550 |
|
<td style="vertical-align: top;">/plugin/part<br> |
| 1551 |
|
</td> |
| 1552 |
|
<td style="vertical-align: top;">Bundle, Composite<br> |
| 1553 |
|
</td> |
| 1554 |
|
<td style="vertical-align: top;">Components in the /plugin/part |
| 1555 |
|
scope are associated with an SWT Composite. Components in this scope |
| 1556 |
|
are given their |
| 1557 |
|
own SWT Composite. They may change the layout on the given Composite, |
| 1558 |
|
but may not change its layout data. The composite will be managed as a |
| 1559 |
|
service, so the component does not need to dispose it. Components in |
| 1560 |
|
this scope may be used as editors, views, or both.<br> |
| 1561 |
|
</td> |
| 1562 |
|
</tr> |
| 1563 |
|
<tr> |
| 1564 |
|
<td style="vertical-align: top;">/plugin/part/view<br> |
| 1565 |
|
</td> |
| 1566 |
|
<td style="vertical-align: top;">Bundle,<br> |
| 1567 |
|
Composite,<br> |
| 1568 |
|
IWorkbenchPage<br> |
| 1569 |
|
</td> |
| 1570 |
|
<td style="vertical-align: top;">All views belong to this scope. |
| 1571 |
|
They are given the IConfigurationElement containing their extension |
| 1572 |
|
markup, and an IWorkbenchPage.<br> |
| 1573 |
|
</td> |
| 1574 |
|
</tr> |
| 1575 |
|
<tr> |
| 1576 |
|
<td style="vertical-align: top;">/plugin/part/editor<br> |
| 1577 |
|
</td> |
| 1578 |
|
<td style="vertical-align: top;">Bundle,<br> |
| 1579 |
|
Composite,<br> |
| 1580 |
|
IWorkbenchPage,<br> |
| 1581 |
|
IEditorInput<br> |
| 1582 |
|
</td> |
| 1583 |
|
<td style="vertical-align: top;">All editors belong to this |
| 1584 |
|
scope. They are given the IConfigurationElement containing their |
| 1585 |
|
extension markup, an IWorkbenchPage, and the IEditorInput containing |
| 1586 |
|
their input.<br> |
| 1587 |
|
</td> |
| 1588 |
|
</tr> |
| 1589 |
|
</tbody> |
| 1590 |
|
</table> |
| 1591 |
|
<br> |
| 1592 |
|
These scopes should be sufficient for most situations. However, some |
| 1593 |
|
plugins may wish to create new scopes in order to pass additional |
| 1594 |
|
context to the objects in an extension point they provided.<br> |
| 1595 |
|
<br> |
| 1596 |
|
Any plugin that defines its own scopes must include its fully qualified |
| 1597 |
|
plugin ID as part of the scope path. For example, if the plugin |
| 1598 |
|
org.eclipse.myplugin extends the /plugin/part/editor scope, the new |
| 1599 |
|
scope name would look like |
| 1600 |
|
/plugin/part/editor/org.eclipse.myplugin.scopename. All scope paths |
| 1601 |
|
that do not contain a period (.) are reserved by the framework.<br> |
| 1602 |
|
<br> |
| 1603 |
|
It is never a breaking change to move a service into a more general |
| 1604 |
|
scope. However, it is always a breaking change to move a service into a |
| 1605 |
|
more specific scope. A service interface may only exist in one scope.<br> |
| 1606 |
|
<h2><a class="mozTocH2" name="mozTocId762751"></a>2.9 Shared Adapters</h2> |
| 1607 |
|
Normally, a new instance of a default interface implementation is |
| 1608 |
|
created for each component that requests it. This allows the adapter to |
| 1609 |
|
keep some state associated with the component and to clean up resources |
| 1610 |
|
once they are no longer needed by the component. However, some |
| 1611 |
|
interface do not need any state or expose any API that could be used to |
| 1612 |
|
create a leak. For example, the IErrorContext interface in section 2.4 |
| 1613 |
|
could safely share one instance between all components in the same |
| 1614 |
|
plugin. In order to reduce memory consumption, the component API should |
| 1615 |
|
support the notion of a shared adapter. A shared adapter will be reused |
| 1616 |
|
in the broadest possible context permitted by its scope. For example, |
| 1617 |
|
an adapter for an interface in the global scope would become a |
| 1618 |
|
singleton, shared adapters in the plugin scope will have at most one |
| 1619 |
|
instance per plugin, and the shared flag will be ignored in the |
| 1620 |
|
/plugin/part scope.<br> |
| 1621 |
|
<br> |
| 1622 |
|
This is intended as a future optimization, and will not be included in |
| 1623 |
|
the initial version of the component framework<br> |
| 1624 |
|
<br> |
| 1625 |
|
<h1><a class="mozTocH1" name="mozTocId707022"></a>3.0 Views and Editors |
| 1626 |
|
as Components</h1> |
| 1627 |
|
This section describes how the workbench uses the component framework |
| 1628 |
|
to create editors and views.<br> |
| 1629 |
|
<br> |
| 1630 |
|
<h2><a class="mozTocH2" name="mozTocId125361"></a>3.1 Interfaces |
| 1631 |
|
offered by the workbench</h2> |
| 1632 |
|
Parent interfaces: (Interfaces given to a component as arguments in its |
| 1633 |
|
constructor)<br> |
| 1634 |
|
<br> |
| 1635 |
|
<table style="width: 100%; text-align: left;" border="1" cellpadding="2" |
| 1636 |
|
cellspacing="2"> |
| 1637 |
|
<tbody> |
| 1638 |
|
<tr> |
| 1639 |
|
<td style="vertical-align: top;">Scope<br> |
| 1640 |
|
</td> |
| 1641 |
|
<td style="vertical-align: top;">Interface<br> |
| 1642 |
|
</td> |
| 1643 |
|
<td style="vertical-align: top;">Description<br> |
| 1644 |
|
</td> |
| 1645 |
|
</tr> |
| 1646 |
|
<tr> |
| 1647 |
|
<td style="vertical-align: top;">/plugin<br> |
| 1648 |
|
</td> |
| 1649 |
|
<td style="vertical-align: top;">IErrorContext<br> |
| 1650 |
|
</td> |
| 1651 |
|
<td style="vertical-align: top;">Provides facilities for logging |
| 1652 |
|
exceptions<br> |
| 1653 |
|
</td> |
| 1654 |
|
</tr> |
| 1655 |
|
<tr> |
| 1656 |
|
<td style="vertical-align: top;">/plugin<br> |
| 1657 |
|
</td> |
| 1658 |
|
<td style="vertical-align: top;">ISwtResources<br> |
| 1659 |
|
</td> |
| 1660 |
|
<td style="vertical-align: top;">Provides facilities for |
| 1661 |
|
allocating SWT resources such as Fonts, Images, and Colors<br> |
| 1662 |
|
</td> |
| 1663 |
|
</tr> |
| 1664 |
|
<tr> |
| 1665 |
|
<td style="vertical-align: top;">/<br> |
| 1666 |
|
</td> |
| 1667 |
|
<td style="vertical-align: top;">INameable<br> |
| 1668 |
|
</td> |
| 1669 |
|
<td style="vertical-align: top;">Parts can use this service to |
| 1670 |
|
change their name, content description, title image, and tooltip. The |
| 1671 |
|
default implementation ignores all method calls.<br> |
| 1672 |
|
</td> |
| 1673 |
|
</tr> |
| 1674 |
|
<tr> |
| 1675 |
|
<td style="vertical-align: top;">/<br> |
| 1676 |
|
</td> |
| 1677 |
|
<td style="vertical-align: top;">IMemento<br> |
| 1678 |
|
</td> |
| 1679 |
|
<td style="vertical-align: top;">Parts will receive a memento |
| 1680 |
|
which they can use to load previously-saved state<br> |
| 1681 |
|
</td> |
| 1682 |
|
</tr> |
| 1683 |
|
<tr> |
| 1684 |
|
<td style="vertical-align: top;">/plugin<br> |
| 1685 |
|
</td> |
| 1686 |
|
<td style="vertical-align: top;">IPartFactory<br> |
| 1687 |
|
</td> |
| 1688 |
|
<td style="vertical-align: top;">Interface that can be used to |
| 1689 |
|
create child views, editors, and other UI parts<br> |
| 1690 |
|
</td> |
| 1691 |
|
</tr> |
| 1692 |
|
<tr> |
| 1693 |
|
<td style="vertical-align: top;">/plugin/part<br> |
| 1694 |
|
</td> |
| 1695 |
|
<td style="vertical-align: top;">IActionBars2<br> |
| 1696 |
|
</td> |
| 1697 |
|
<td style="vertical-align: top;">Interface used to add to the |
| 1698 |
|
toolbar, cool bar, etc. Currently exposed on the view site.<br> |
| 1699 |
|
</td> |
| 1700 |
|
</tr> |
| 1701 |
|
<tr> |
| 1702 |
|
<td style="vertical-align: top;"><br> |
| 1703 |
|
</td> |
| 1704 |
|
<td style="vertical-align: top;"><br> |
| 1705 |
|
</td> |
| 1706 |
|
<td style="vertical-align: top;"><br> |
| 1707 |
|
</td> |
| 1708 |
|
</tr> |
| 1709 |
|
</tbody> |
| 1710 |
|
</table> |
| 1711 |
|
<br> |
| 1712 |
|
Child interfaces: (Services that a component offers to its parent - |
| 1713 |
|
either by implementing directly or as an adapter)<br> |
| 1714 |
|
<br> |
| 1715 |
|
<table style="text-align: left; width: 1550px; height: 88px;" border="1" |
| 1716 |
|
cellpadding="2" cellspacing="2"> |
| 1717 |
|
<tbody> |
| 1718 |
|
<tr> |
| 1719 |
|
<td style="vertical-align: top;">Scope<br> |
| 1720 |
|
</td> |
| 1721 |
|
<td style="vertical-align: top;">Interface<br> |
| 1722 |
|
</td> |
| 1723 |
|
<td style="vertical-align: top;">Description<br> |
| 1724 |
|
</td> |
| 1725 |
|
</tr> |
| 1726 |
|
<tr> |
| 1727 |
|
<td style="vertical-align: top;">/plugin/part<br> |
| 1728 |
|
</td> |
| 1729 |
|
<td style="vertical-align: top;">IFocusable<br> |
| 1730 |
|
</td> |
| 1731 |
|
<td style="vertical-align: top;">Parts can implement this service |
| 1732 |
|
to allow their parent<br> |
| 1733 |
|
</td> |
| 1734 |
|
</tr> |
| 1735 |
|
<tr> |
| 1736 |
|
<td style="vertical-align: top;">/<br> |
| 1737 |
|
</td> |
| 1738 |
|
<td style="vertical-align: top;">IMultiPart<br> |
| 1739 |
|
</td> |
| 1740 |
|
<td style="vertical-align: top;">Parts should implement this if |
| 1741 |
|
they contain other parts and have the notion of an "active" child. |
| 1742 |
|
Other services can use this service if their default implementation |
| 1743 |
|
should redirect to the active child.<br> |
| 1744 |
|
</td> |
| 1745 |
|
</tr> |
| 1746 |
|
<tr> |
| 1747 |
|
<td style="vertical-align: top;">/<br> |
| 1748 |
|
</td> |
| 1749 |
|
<td style="vertical-align: top;">IPersistable<br> |
| 1750 |
|
</td> |
| 1751 |
|
<td style="vertical-align: top;">Parts may implement this |
| 1752 |
|
interface if they wish to save their state between sessions.<br> |
| 1753 |
|
</td> |
| 1754 |
|
</tr> |
| 1755 |
|
<tr> |
| 1756 |
|
<td style="vertical-align: top;"><br> |
| 1757 |
|
</td> |
| 1758 |
|
<td style="vertical-align: top;"><br> |
| 1759 |
|
</td> |
| 1760 |
|
<td style="vertical-align: top;"><br> |
| 1761 |
|
</td> |
| 1762 |
|
</tr> |
| 1763 |
|
</tbody> |
| 1764 |
|
</table> |
| 1765 |
|
<br> |
| 1766 |
|
<br> |
| 1767 |
|
<h3><a class="mozTocH2" name="mozTocId163729"></a>3.1.1 IMultiPart: |
| 1768 |
|
Redirecting |
| 1769 |
|
adapters from the active child<br> |
| 1770 |
|
</h3> |
| 1771 |
In UI code, it is common to create aggregate components that have an |
In UI code, it is common to create aggregate components that have an |
| 1772 |
"active" child. Many of the adapters that the aggregate offers its |
"active" child. This section suggests a general pattern for redirecting |
| 1773 |
parent will redirect their implementation to the active child. We refer |
components in this way. Many of the adapters that the aggregate offers |
| 1774 |
to this as "multiplexing" the service. The aggregate itself will know |
its |
| 1775 |
|
parent will redirect their implementation to the active child. The |
| 1776 |
|
aggregate itself will know |
| 1777 |
how to select its active child, but it may not know about all the |
how to select its active child, but it may not know about all the |
| 1778 |
services that need to be multiplexed. The default implementation of a |
interfaces that need to be redirected in this manner. The default |
| 1779 |
service determines how and if it should be multiplexed.<br> |
implementation of an interface determines how it should be redirected.<br> |
| 1780 |
<br> |
<br> |
| 1781 |
This can be explained better using a concrete example. Workbench parts |
This can be shown using a concrete example. Workbench parts |
| 1782 |
offer an IFocusable adapter to their parent that allows their parent to |
offer an IFocusable adapter to their parent that allows their parent to |
| 1783 |
give them focus. <br> |
give them focus. <br> |
| 1784 |
<br> |
<br> |
| 1801 |
implement the IFocusable interface, it should redirect focus to its |
implement the IFocusable interface, it should redirect focus to its |
| 1802 |
active child. If the part doesn't have an active child, focus should go |
active child. If the part doesn't have an active child, focus should go |
| 1803 |
directly to the part's main control. To supply this default behavior, |
directly to the part's main control. To supply this default behavior, |
| 1804 |
we provide an implementation of IFocusable as a global service:<br> |
we provide a default implementation of IFocusable:<br> |
| 1805 |
<br> |
<br> |
| 1806 |
<code></code> |
<code></code> |
| 1807 |
<div style="margin-left: 40px;"><code>/**<br> |
<div style="margin-left: 40px;"><code>/**<br> |
| 1813 |
public class DefaultFocusable implements IFocusable {<br> |
public class DefaultFocusable implements IFocusable {<br> |
| 1814 |
<br> |
<br> |
| 1815 |
private Composite control;<br> |
private Composite control;<br> |
| 1816 |
private IMultiplexer activePart;<br> |
private IMultiPart activePart;<br> |
| 1817 |
<br> |
<br> |
| 1818 |
/**<br> |
/**<br> |
| 1819 |
* Creates the default implementation of |
* Creates the default implementation of |
| 1820 |
IFocusable, given the main control<br> |
IFocusable, given the main control<br> |
| 1821 |
* of the part and an IMultiplexer that can be |
* of the part and an IMultiPart that can be |
| 1822 |
queried for the active child.<br> |
queried for the active child.<br> |
| 1823 |
* <br> |
* <br> |
| 1824 |
* @param toGiveFocus main control of the pane<br> |
* @param toGiveFocus main control of the pane<br> |
| 1826 |
returns the active part<br> |
returns the active part<br> |
| 1827 |
*/<br> |
*/<br> |
| 1828 |
public DefaultFocusable(Composite toGiveFocus, |
public DefaultFocusable(Composite toGiveFocus, |
| 1829 |
IMultiplexer activePartProvider) {<br> |
IMultiPart activePartProvider) {<br> |
| 1830 |
control = toGiveFocus;<br> |
control = toGiveFocus;<br> |
| 1831 |
activePart = activePartProvider;<br> |
activePart = activePartProvider;<br> |
| 1832 |
}<br> |
}<br> |
| 1862 |
}</code><br> |
}</code><br> |
| 1863 |
<br> |
<br> |
| 1864 |
</div> |
</div> |
| 1865 |
Here is the XML markup to register the service:<br> |
Here is the XML markup to register the interface:<br> |
| 1866 |
<br> |
<br> |
| 1867 |
<div style="margin-left: 40px;"><code><service<br> |
<div style="margin-left: 40px;"><code><service<br> |
| 1868 |
|
|
| 1869 |
interface="org.eclipse.ui.workbench.services.IFocusable"<br> |
interface="org.eclipse.ui.workbench.services.IFocusable"<br> |
| 1870 |
|
|
| 1871 |
class="org.eclipse.ui.internal.part.serviceimplementation.DefaultFocusable"/></code><code></code><br> |
class="org.eclipse.ui.internal.part.serviceimplementation.DefaultFocusable<br> |
| 1872 |
|
childadapter="true"<br> |
| 1873 |
|
scope="plugin/part"/></code><code></code><br> |
| 1874 |
</div> |
</div> |
| 1875 |
<br> |
<br> |
| 1876 |
All of the services we have looked at so far have been offered by a |
All of the interfaces we have looked at so far have been offered by a |
| 1877 |
parent for use in a child's constructor. In this case, the service is |
parent for use in a child's constructor. In this case, the interface is |
| 1878 |
offered as an adapter on the child to be used by the parent. In both |
offered as an adapter on the child to be used by the parent. In both |
| 1879 |
cases, the service is declared in the same way. Any service that |
cases, we support the notion of a default implementation that is |
| 1880 |
supports multiplexing takes an IMultiplexer in its constructor. If the |
declared through XML. Any service that should be redirected based on |
| 1881 |
part does not support multiplexing, the IMultiplexer will always |
the active child will take IMultiPart in its constructor. Here is an |
| 1882 |
returns null from getCurrent. Here is an example part that supports |
example part that supports |
| 1883 |
multiplexing:<br> |
multiplexing:<br> |
| 1884 |
<code><br> |
<code><br> |
| 1885 |
</code> |
</code> |
| 1924 |
private IContainer page1;<br> |
private IContainer page1;<br> |
| 1925 |
private IContainer page2;<br> |
private IContainer page2;<br> |
| 1926 |
<br> |
<br> |
| 1927 |
// Helper class that implements the IMultiplexer |
// Helper class that implements the IMultiPart |
| 1928 |
interface<br> |
interface<br> |
| 1929 |
private Multiplexer multiplexer = new Multiplexer();<br> |
private Multiplexer multiplexer = new Multiplexer();<br> |
| 1930 |
private Button checkBox;<br> |
private Button checkBox;<br> |
| 2023 |
viewContainer.dispose();<br> |
viewContainer.dispose();<br> |
| 2024 |
</code><code></code></div> |
</code><code></code></div> |
| 2025 |
<code> <br> |
<code> <br> |
| 2026 |
</code>This example also shows how the same service can work for both |
</code>This example also shows how the same default implementation can |
| 2027 |
|
work for both |
| 2028 |
multiplexing and non-multiplexing parts. The Page2 class doesn't |
multiplexing and non-multiplexing parts. The Page2 class doesn't |
| 2029 |
implement IFocusable or IMultiplexing part, but we are still able to |
implement IFocusable or IMultiPart, but we are still able to |
| 2030 |
ask for an IFocusable interface and use it to give focus to the part.<br> |
ask for an IFocusable interface and use it to give focus to the part.<br> |
| 2031 |
<h1><a class="mozTocH1" name="mozTocId707022"></a>3.0 Views and Editors |
<span style="font-weight: bold;"><br> |
| 2032 |
as Components</h1> |
</span><span style="font-weight: bold;"></span> |
| 2033 |
TODO<br> |
<h3><a class="mozTocH3" name="mozTocId483376"></a>3.1.2 INameable: |
| 2034 |
|
Changing the name of a part</h3> |
| 2035 |
|
In order to change their name, existing parts need to implement a set |
| 2036 |
|
of get methods, maintain a listener list, and send notifications when |
| 2037 |
|
their name changes. Component-based parts will change their name by |
| 2038 |
|
using an INameable interface provided by their parent. INameable looks |
| 2039 |
|
like this:<br> |
| 2040 |
<br> |
<br> |
| 2041 |
|
<div style="margin-left: 40px;"><code>public interface INameable {<br> |
| 2042 |
|
public void setName(String newName);<br> |
| 2043 |
|
public void setContentDescription(String |
| 2044 |
|
contentDescription);<br> |
| 2045 |
|
public void setImage(Image theImage);<br> |
| 2046 |
|
public void setTooltip(String toolTip);<br> |
| 2047 |
|
}<br> |
| 2048 |
|
<br> |
| 2049 |
|
</code></div> |
| 2050 |
|
For example, a view could set its name like this:<br> |
| 2051 |
|
<br> |
| 2052 |
|
<div style="margin-left: 40px;"><code>public class MyView {<br> |
| 2053 |
|
public MyView(Composite parent, INameable name) {<br> |
| 2054 |
|
name.setName("Some tab text");<br> |
| 2055 |
|
}<br> |
| 2056 |
|
}<br> |
| 2057 |
<br> |
<br> |
| 2058 |
|
</code></div> |
| 2059 |
|
If a parent cares about the names of its children, it should provide an |
| 2060 |
|
implementation of INameable that reacts when the child changes its |
| 2061 |
|
name. Otherwise, the child will be given a default implementation of |
| 2062 |
|
INameable that ignores all method calls. This eliminates the need to |
| 2063 |
|
attach listeners to views.<br> |
| 2064 |
|
<h3><a class="mozTocH3" name="mozTocId969580"></a>3.1.3 IPartFactory: |
| 2065 |
|
Creating child parts<br> |
| 2066 |
|
</h3> |
| 2067 |
|
Any part that wants to create other nested parts would use an |
| 2068 |
|
IPartFactory interface.<br> |
| 2069 |
|
<br> |
| 2070 |
|
<div style="margin-left: 40px;"><code>public interface IPartFactory {<br> |
| 2071 |
|
public IContainer createView(String viewId, |
| 2072 |
|
Composite parentComposite, IWorkbenchPage page, IContainerFactory |
| 2073 |
|
services);<br> |
| 2074 |
|
public IContainer createEditor(String editorId, |
| 2075 |
|
Composite parentComposite, IWorkbenchPage page, </code><code>IEditorInput |
| 2076 |
|
input, </code><code>IContainerFactory services);<br> |
| 2077 |
|
public IContainer createPart(String partId, |
| 2078 |
|
Composite parentComposite, IContainerFactory services);<br> |
| 2079 |
|
}</code><br> |
| 2080 |
|
<br> |
| 2081 |
|
<br> |
| 2082 |
|
</div> |
| 2083 |
|
<div style="margin-left: 40px;"><code></code><code></code></div> |
| 2084 |
|
<span style="font-weight: bold;"></span> |
| 2085 |
</body> |
</body> |
| 2086 |
</html> |
</html> |