| <html> |
| <head> |
| <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title>Eclipse RCP Architecture Application Architecture</title> |
| <link href="../default_style.css" rel="stylesheet"> |
| <link rel="stylesheet" type="text/css" href="article.css"> |
| </head> |
| <body> |
| <div align="right">© Copyright 2006The Eclipse Foundation</div> |
| <h1>Eclipse RCP Architecture Application Architecture</h1> |
| |
| <p> |
| The Equinox implementation of OSGi R4 is one of the most |
| compelling features of the Eclipse Rich Client Platform |
| (RCP). At its heart, Equinox is a powerful component |
| management system that provides incredible value to your |
| application: but only if you architect your application to |
| leverage that power. With Equinox, it is possible to |
| architect an application as a composition of components. The |
| benefits of doing so are many. |
| </p> |
| |
| <p> |
| Architectually speaking, separating an application into |
| components encourages separation of the application code |
| into layers. The model-view-controller pattern is an example |
| of a layered architecture that separates the application's |
| concerns into multiple layers. The model layer implements |
| the domain specific business logic for your application. |
| </p> |
| |
| <p> |
| An application, factored into multiple layers, is generally |
| easier to enhance and maintain. Ideally, each layer contains |
| code that is specifically focused on that layer (no view |
| code in the model layer) which makes the layer potentially |
| reusable. A well-designed model layer can be used in both |
| your Eclipse RCP application and your web application, for |
| example. By putting your data management logic into a |
| separate layer, it becomes easier to change or completely |
| replace that layer without change rippling across the entire |
| code base. At a minimum, each layer of your application can |
| be built as a separate component. |
| </p> |
| |
| <p> |
| When Eclipse starts up, it loads the minimum set of |
| components required by the environment to function. |
| Additional components are then loaded as they are required. |
| This significantly reduces the start up time required by the |
| application. |
| </p> |
| |
| <p> |
| An application composed of multiple components is generally |
| easier to update than one built as a single monolithic |
| component. Individual components, each containing some part |
| of the functionality can potentially be updated |
| individually; this reduces the amount of time required to |
| download and install updates. Of course this comes at the |
| expense of potentially increased complexity in managing |
| relationships and dependencies among components. |
| </p> |
| |
| <p> |
| Version management makes updating components actually work. |
| </p> |
| |
| <p> |
| An application composed of multiple components is generally |
| easy to extend. In fact, it is possible to--when |
| necessary--completely replace components to radically change |
| the behaviour of the application while minimizing the impact |
| of the rest of the code. Some ISVs use components to |
| customize the behaviour of their application for individual |
| customers without forking the code base. |
| </p> |
| |
| <p> |
| A large number of small components make updating your |
| application easier. Rather than updating one huge monolithic |
| application runtime, you can update individual components. |
| The Eclipse Update Manager--in conjunction with an update |
| site--even does most of the heavy lifting for you. In |
| addition to the update benefit, a collection of components |
| is better able to take advantage of the lazy-loading feature |
| provided by Equinox. Equinox loads components only when they |
| are needed; this reduces the time and effort required when |
| the application initial starts up which improves the user's |
| experience. |
| </p> |
| |
| <p> |
| Perhaps one of the more significant advantages of the |
| Equinox component model is the management of dependencies |
| between components. All components must explicitly declare |
| their dependencies on other components. In the Equinox |
| environment, when a component is required, all of the |
| components that it is dependent on are loaded before the |
| component itself (naturally). More importantly, Equinox |
| insulates components from other unrelated components. That |
| is, a component can only directly access the elements |
| contained within the components it is dependent upon. All |
| other components cannot be referenced and will not |
| interfere. |
| </p> |
| |
| <p> |
| It is possible that two completely independent (i.e. no |
| direct dependencies) components can define classes with the |
| same full name and there is no conflict (contrast this with |
| standard Java in which the class that appears earliest on |
| the classpath wins). This extends to multiple versions of a |
| single component: it is possible to have individual plug-ins |
| reference different versions of the same component. Multiple |
| versions of the same component can run concurrently within |
| the environment without conflicting with one-another (this |
| works so long as the plug-in does not contribute anything to |
| the user interface; that just gets weird). |
| </p> |
| |
| <h2>Balancing Act</h2> |
| |
| <p> |
| Architecting an application as a large collection of small |
| scale plug-ins can make it relatively easy to update your |
| application and potentially reduce startup time. However, a |
| large collection of plug-ins requires complex dependency |
| management and ultimately increases the runtime overhead of |
| the application. Managing that complexity can be an |
| incredible burden. As such, deciding on exactly how you |
| should divide your code into separate components takes some |
| effort. |
| </p> |
| |
| <p> |
| On one extreme, you can build your application so that each |
| component contains a single class. On the other extreme, you |
| can build a single component for your application that |
| contains everything. The right solution lies somewhere in |
| the middle. |
| </p> |
| |
| <h2>Observer Pattern</h2> |
| |
| <p> |
| Very often there is a huge divide between the ideological |
| theory and the practical reality. That is, it is easy to say |
| that multiple components are good and that they should be |
| used, but how do you actually make it work? |
| </p> |
| |
| <p> |
| The observer pattern is an important mechanism for making a |
| proper separation of components work. This pattern is not |
| specific to Eclipse or even to Java (it is used extensively |
| Smalltalk and in other languages). It is one of the key |
| features of the JavaBeans specification. |
| </p> |
| |
| <p> |
| Essentially, the observer pattern is used by one object to |
| watch changes in another without building a formal |
| relationship. Rather than the observed object knowing |
| anything specific about the observing objects, the observed |
| object instead fires the moral equivalent of an event. The |
| event comes in the form of a message being sent to a |
| listener object that is registered by the observer. The |
| windowing system that underlies Eclipse, the Standard Widget |
| Toolkit (SWT), does exactly this. |
| </p> |
| |
| <p> |
| |
| <a href="#listener">Listing XX</a> |
| shows a fragment of application code that creates a new SWT |
| Canvas and adds a paint listener to it. |
| </p> |
| |
| <div class="listing"> |
| <h3> |
| <a name="listener"></a>Listing XX: Registering a listener on an SWT Canvas</h3> |
| <pre> |
| |
| canvas = new Canvas(parent, SWT.NONE); |
| canvas.addPaintListener(new PaintListener() { |
| public void paint(PaintEvent event) { |
| event.gc.drawRectangle(10,10,50,50); |
| } |
| }); |
| </pre> |
| </div> |
| |
| <p> |
| When it is time for this canvas to be redrawn (either when |
| the canvas is exposed or it is explicitly asked to redraw), |
| it will send the |
| addPaintListener() |
| message to all of the registered listeners. |
| </p> |
| |
| <p> |
| This pattern is leveraged throughout the Eclipse code. Some |
| components register with the workbench selection service; |
| doing so invokes the listener whenever a selection occurs in |
| a view or editor. The Eclipse Corner Article |
| <a href="#http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html"> |
| Eclipse Workbench: Using the Selection Service |
| </a> |
| discusses the selection service in detail. |
| </p> |
| |
| <p>This pattern can be leveraged in your code.</p> |
| |
| |
| <p> |
| One of the things that I implemented with the Sudoku game |
| was a disconnect between the model and the view. I provided |
| a representation of a Sudoku game that knows nothing of user |
| interface. It knows about cells and boxes and numbers; it |
| also knows if any given cell is considered valid. It knows |
| nothing about what colour should be used to draw a cell, how |
| thick the lines should be, or anything else that has |
| anything to do with drawing. |
| </p> |
| |
| <p> |
| To help with the drawing part, and to avoid having to |
| continually recompute position information for individual |
| cells, I introduced the notion of a CellDrawer that does |
| know about colours, and line thickness, and such. It also |
| knows--in absolute coordinates--where to draw the cell. This |
| class is part of the user interface code. |
| </p> |
| |
| <p> |
| I set up the Sudoku board so that it can be observed. |
| Interested parties, like a user interface, can register |
| event listeners that are triggered when a change occurs on |
| the board. I use the listeners consistently. When the user |
| clicks on the board or types a key, the user interface |
| translates that operation into a command that's passed to |
| the Sudoko board. The command is along the lines of "set the |
| value of the cell at position (5,4) to 7" (position is the |
| relative position of a cell, not a screen co-ordinate). The |
| board makes the necessary modifications and fires an event |
| to inform interested parties of the change. The user |
| interface is one of the interested parties, and when it |
| receives the event it redraws the board. I could have done |
| this a lot simpler: when the user clicks or types a key, |
| change the board and then get the user interface to redraw. |
| Why not just do this? Why all the extra event stuff? |
| </p> |
| |
| <p> |
| Well... Chris answered this question pretty well. In a few |
| minutes on a plane, Chris added an ECF component to the |
| game: he made the Sudoku game multi-player. He did it |
| without interacting with the user interface, he just worked |
| directly with the model. When the remote user makes a |
| change, a message is sent. When that message is received, |
| the model is modified which causes an event to be triggered |
| resulting in the user interface updating. Pretty cool. And, |
| a fine example of extending a system in a way that the |
| original author had never considered. |
| </p> |
| |
| <p> |
| I use the event in other places as well. The solver included |
| with the implementation modify the model which then triggers |
| an update of the user interface. The solvers know nothing |
| about the user interface. |
| </p> |
| |
| <p> |
| At some point, I'll probably add a couple more views to the |
| game. An obvious view might show some statistics: how many |
| cells are left, how long as the game been going, how many |
| times has a particular cell been changed, etc. This view |
| will also just register itself to receive changed events |
| from the board and update itself whenever those events are |
| triggered. My main user interface will not have to know |
| anything about this new view and so will be totally |
| decoupled; but it will appear to the user to be tightly |
| integrated. Very cool. |
| </p> |
| |
| <p> |
| This relationship is described by the Observer Pattern. It's |
| used extensively throughout the Eclipse code (including SWT) |
| and all over the place in Java. Heck, we even used it in |
| (wait for it, Denis...) Smalltalk! It's a pretty powerful |
| mechanism that may require a little bit of work up front, |
| but sure makes building applications a lot easier. |
| </p> |
| |
| <h2>Applying the Theory</h2> |
| |
| <p> |
| As a starting point, divide your application into separate |
| plug-ins for the model and view. Ideally, a separate plug-in |
| to manage data concerns (i.e. storing and retrieving your |
| objects from a data source) should be considered as well. |
| </p> |
| |
| <p> |
| After that, it may be desireable to build separate plug-ins |
| along functionality lines. |
| </p> |
| |
| </body> |
| </html> |