SpeADL Minus Tutorial » Historique » Version 8
Anonyme, 06/10/2014 17:08
| 1 | 1 | Anonyme | h1. SpeADL Minus Tutorial |
|---|---|---|---|
| 2 | |||
| 3 | 4 | Anonyme | {{>toc}} |
| 4 | |||
| 5 | 1 | Anonyme | This is a tutorial for [[SpeADL Minus Reference|SpeADL⁻]]: creating a project, defining simple and composite components, implementing components. |
| 6 | |||
| 7 | h2. Objectives |
||
| 8 | |||
| 9 | The objective of this tutorial is to understand the basic workflow to follow when developing component-oriented applications with SpeADL in Eclipse/MAY. |
||
| 10 | |||
| 11 | We will create a simple composition of two components connected together following a typical client-server configuration. |
||
| 12 | The server will provide a service that will be used by the client. |
||
| 13 | They will be composed together in a big component. |
||
| 14 | 7 | Anonyme | An Java Application will be created to show how to execute the composition from Java. |
| 15 | A very simple GUI will be used to illustrate a self-contained component acting as an application. |
||
| 16 | 1 | Anonyme | |
| 17 | h2. Installing Eclipse and MAY |
||
| 18 | |||
| 19 | This procedure is described on [[SpeADL MAY Project SetUp|this page]]. |
||
| 20 | |||
| 21 | h2. Creating a New Project |
||
| 22 | |||
| 23 | First, we must create a project to work. |
||
| 24 | |||
| 25 | In Eclipse, go to the menus : *File / New / Java Project*. |
||
| 26 | |||
| 27 | Enter _Tutorial 1_ as the project name, verify that the *execution environment JRE* is 1.5 or above. |
||
| 28 | |||
| 29 | As a start, create a package in the *src* folder called _tutorial1_. |
||
| 30 | |||
| 31 | h2. The Server Component |
||
| 32 | |||
| 33 | 3 | Anonyme | h3. Organisation |
| 34 | |||
| 35 | 1 | Anonyme | Create the following hierarchy of packages (See [[SpeADL Best Practices#Project Organisation|this best practice]] for details on the matter): |
| 36 | * _tutorial1.server_ |
||
| 37 | ** _impl_ |
||
| 38 | ** _interfaces_ |
||
| 39 | |||
| 40 | 3 | Anonyme | h3. Defining the Component |
| 41 | |||
| 42 | 2 | Anonyme | Create a SpeADL file: |
| 43 | * Right-click on tutorial1.server and select *New / File*. |
||
| 44 | * Enter _server.speadl_ as the file name. |
||
| 45 | 1 | Anonyme | |
| 46 | Define the namespace we are going to work in as well as the _Server_ component: |
||
| 47 | <pre> |
||
| 48 | namespace tutorial1.server { |
||
| 49 | component ServerComponentType { |
||
| 50 | |||
| 51 | 3 | Anonyme | } |
| 52 | } |
||
| 53 | </pre> |
||
| 54 | |||
| 55 | Save and confirm that the *speadl-gen* folder was automatically added to the project source folders and that it contains a Java class generated in the package _tutorial1.server_ named _ServerComponentType_. |
||
| 56 | |||
| 57 | h3. Defining a Port and its Interface |
||
| 58 | |||
| 59 | The _Server_ component will provide a port whose interface contains one method to give the contrary of a boolean. |
||
| 60 | |||
| 61 | Add it to the component declaration: |
||
| 62 | <pre> |
||
| 63 | namespace tutorial1.server { |
||
| 64 | component ServerComponentType { |
||
| 65 | provides service: NotSoNiceServiceType |
||
| 66 | } |
||
| 67 | } |
||
| 68 | </pre> |
||
| 69 | |||
| 70 | Because the _NotSoNiceServiceType_ interface does not yet exist, there is an error in the SpeADL editor. |
||
| 71 | We will store the interface in the _tutorial1.server.interfaces_ package. |
||
| 72 | |||
| 73 | Either create it by hand or use the Quick Fix proposed by SpeADL editor by hovering on the error. |
||
| 74 | <pre> |
||
| 75 | package tutorial1.server.interfaces; |
||
| 76 | |||
| 77 | public interface NotSoNiceServiceType { |
||
| 78 | |||
| 79 | public boolean contrary(boolean b); |
||
| 80 | } |
||
| 81 | </pre> |
||
| 82 | |||
| 83 | Save, and go back to the SpeADL editor for _server.speadl_. |
||
| 84 | Call the automatic import organiser with *Ctrl+Shift+O*. |
||
| 85 | Confirm that an import was added on top of the SpeADL file and save. |
||
| 86 | |||
| 87 | h3. Implementing the Component |
||
| 88 | |||
| 89 | Create a new Java class in _tutorial1.server.impl_ named ServerImpl, and edit it so that it extends ServerComponentType: |
||
| 90 | <pre> |
||
| 91 | 5 | Anonyme | public class ServerImpl extends ServerComponentType { |
| 92 | 3 | Anonyme | |
| 93 | } |
||
| 94 | </pre> |
||
| 95 | |||
| 96 | Notice that completion can be exploited as _ServerComponentType_ is an actual Java type, but that calling *F3* on it redirects directly to the SpeADL file. |
||
| 97 | |||
| 98 | Because there is abstract method to implement in _ServerComponentType_, there is errors in the Java editor. |
||
| 99 | Use the Quick Fix *Add unimplemented methods* by hovering on the error on the class name _ServerImpl_: |
||
| 100 | <pre> |
||
| 101 | public class ServerImpl extends ServerComponentType { |
||
| 102 | |||
| 103 | @Override |
||
| 104 | protected NotSoNiceServiceType make_service() { |
||
| 105 | // TODO Auto-generated method stub |
||
| 106 | return null; |
||
| 107 | } |
||
| 108 | |||
| 109 | } |
||
| 110 | </pre> |
||
| 111 | |||
| 112 | Remove the *TODO* line and replace _null_ with _new NotSoNiceServiceType_, call completion (*Ctrl+Space*) and choose *NotSoNiceServiceType() Anonymous Inner Type*: |
||
| 113 | <pre> |
||
| 114 | public class ServerImpl extends ServerComponentType { |
||
| 115 | |||
| 116 | @Override |
||
| 117 | protected NotSoNiceServiceType make_service() { |
||
| 118 | return new NotSoNiceServiceType() { |
||
| 119 | |||
| 120 | @Override |
||
| 121 | public boolean contrary(boolean b) { |
||
| 122 | // TODO Auto-generated method stub |
||
| 123 | return false; |
||
| 124 | 1 | Anonyme | } |
| 125 | }; |
||
| 126 | 4 | Anonyme | } |
| 127 | } |
||
| 128 | </pre> |
||
| 129 | |||
| 130 | Remove the *TODO* line and replace _return false;_ by _return !b;_: |
||
| 131 | <pre> |
||
| 132 | package tutorial1.server.impl; |
||
| 133 | |||
| 134 | import tutorial1.server.ServerComponentType; |
||
| 135 | import tutorial1.server.interfaces.NotSoNiceServiceType; |
||
| 136 | |||
| 137 | public class ServerImpl extends ServerComponentType { |
||
| 138 | |||
| 139 | @Override |
||
| 140 | protected NotSoNiceServiceType make_service() { |
||
| 141 | return new NotSoNiceServiceType() { |
||
| 142 | |||
| 143 | @Override |
||
| 144 | public boolean contrary(boolean b) { |
||
| 145 | return !b; |
||
| 146 | } |
||
| 147 | }; |
||
| 148 | } |
||
| 149 | |||
| 150 | } |
||
| 151 | </pre> |
||
| 152 | |||
| 153 | 1 | Anonyme | h2. The Client Component |
| 154 | 4 | Anonyme | |
| 155 | h3. Organisation |
||
| 156 | |||
| 157 | 5 | Anonyme | Create the following hierarchy of packages: |
| 158 | 4 | Anonyme | * _tutorial1.client_ |
| 159 | ** _impl_ |
||
| 160 | ** _interfaces_ |
||
| 161 | ** _datatypes_ |
||
| 162 | |||
| 163 | h3. Defining the Component |
||
| 164 | |||
| 165 | Create a SpeADL file in _tutorial1.client_ named _client.speadl_. |
||
| 166 | |||
| 167 | Define the namespace we are going to work in as well as the _Client_ component: |
||
| 168 | <pre> |
||
| 169 | namespace tutorial1.client { |
||
| 170 | component ClientComponentType { |
||
| 171 | |||
| 172 | } |
||
| 173 | } |
||
| 174 | </pre> |
||
| 175 | |||
| 176 | Save and confirm that the *speadl-gen* folder contains a Java class generated in the package _tutorial1.client_ named _ClientComponentType_. |
||
| 177 | |||
| 178 | h3. Defining the Ports, their Interfaces and Datatypes |
||
| 179 | |||
| 180 | The Client component will provides a port computing a request and will need the _NotSoNiceServiceType_ to do its job: |
||
| 181 | <pre> |
||
| 182 | import tutorial1.server.interfaces.NotSoNiceServiceType |
||
| 183 | |||
| 184 | namespace tutorial1.client { |
||
| 185 | |||
| 186 | component ClientComponentType { |
||
| 187 | provides service: ASupeNiceService |
||
| 188 | requires helper: NotSoNiceServiceType |
||
| 189 | } |
||
| 190 | |||
| 191 | } |
||
| 192 | </pre> |
||
| 193 | |||
| 194 | Don't hesitate to exploit completion (*Ctrl+Space*) and automatic import organiser (*Ctrl+Shift+O*) to type the interfaces names. |
||
| 195 | |||
| 196 | As before, an error appears in the editor because _ASupeNiceService_ does not exists, create it in _tutorial1.client.interfaces_: |
||
| 197 | <pre> |
||
| 198 | package tutorial1.client.interfaces; |
||
| 199 | |||
| 200 | public interface ASupeNiceService { |
||
| 201 | |||
| 202 | 1 | Anonyme | public Request compute(Request r); |
| 203 | |||
| 204 | 4 | Anonyme | } |
| 205 | </pre> |
||
| 206 | |||
| 207 | 5 | Anonyme | As we can see, we rely on a type named _Request_. |
| 208 | Create it in _tutorial1.client.datatypes_: |
||
| 209 | 4 | Anonyme | <pre> |
| 210 | package tutorial1.client.datatypes; |
||
| 211 | |||
| 212 | public class Request { |
||
| 213 | |||
| 214 | public final boolean b; |
||
| 215 | 1 | Anonyme | |
| 216 | public Request(boolean b) { |
||
| 217 | this.b = b; |
||
| 218 | } |
||
| 219 | } |
||
| 220 | </pre> |
||
| 221 | 5 | Anonyme | |
| 222 | h3. Implementing the Component |
||
| 223 | |||
| 224 | Create a new Java class in tutorial1.client.impl named ClientImpl. |
||
| 225 | Edit it so that it extends _ClientComponentType_ and resolve all the errors to generate its complete skeleton: |
||
| 226 | <pre> |
||
| 227 | package tutorial1.client.impl; |
||
| 228 | |||
| 229 | import tutorial1.client.ClientComponentType; |
||
| 230 | import tutorial1.client.datatypes.Request; |
||
| 231 | import tutorial1.client.interfaces.ASupeNiceService; |
||
| 232 | |||
| 233 | public class ClientImpl extends ClientComponentType { |
||
| 234 | |||
| 235 | @Override |
||
| 236 | protected ASupeNiceService make_service() { |
||
| 237 | return new ASupeNiceService() { |
||
| 238 | |||
| 239 | @Override |
||
| 240 | public Request compute(Request r) { |
||
| 241 | // TODO Auto-generated method stub |
||
| 242 | return null; |
||
| 243 | } |
||
| 244 | }; |
||
| 245 | } |
||
| 246 | |||
| 247 | } |
||
| 248 | </pre> |
||
| 249 | |||
| 250 | Implement the _compute()_ method to call the required port _helper_ to actually do the computation and to return a new _Request_: |
||
| 251 | <pre> |
||
| 252 | public class ClientImpl extends ClientComponentType { |
||
| 253 | |||
| 254 | @Override |
||
| 255 | protected ASupeNiceService make_service() { |
||
| 256 | return new ASupeNiceService() { |
||
| 257 | @Override |
||
| 258 | public Request compute(Request r) { |
||
| 259 | final boolean contrary = requires().helper().contrary(r.b); |
||
| 260 | return new Request(contrary); |
||
| 261 | } |
||
| 262 | }; |
||
| 263 | } |
||
| 264 | } |
||
| 265 | </pre> |
||
| 266 | |||
| 267 | h2. The Composite Component |
||
| 268 | |||
| 269 | In order to use the Client and the Server components together, we need to build a composite component connecting them together. |
||
| 270 | |||
| 271 | 1 | Anonyme | h3. Defining the Component |
| 272 | |||
| 273 | Create a SpeADL file in _tutorial1.composite_ named _composite.speadl_. |
||
| 274 | 5 | Anonyme | |
| 275 | 7 | Anonyme | Define the namespace we are going to work in as well as the _CompositeComponent_ component: |
| 276 | 5 | Anonyme | <pre> |
| 277 | 6 | Anonyme | namespace tutorial1.composite { |
| 278 | 7 | Anonyme | component CompositeComponent { |
| 279 | 5 | Anonyme | |
| 280 | } |
||
| 281 | } |
||
| 282 | 1 | Anonyme | </pre> |
| 283 | 5 | Anonyme | |
| 284 | 1 | Anonyme | Save. |
| 285 | 5 | Anonyme | |
| 286 | 1 | Anonyme | h3. Defining the Composition |
| 287 | 5 | Anonyme | |
| 288 | 7 | Anonyme | In CompositeComponent, there will be one server and one client for now. |
| 289 | 6 | Anonyme | Declare them as parts in the composite component: |
| 290 | 1 | Anonyme | <pre> |
| 291 | 5 | Anonyme | import tutorial1.client.ClientComponentType |
| 292 | import tutorial1.server.ServerComponentType |
||
| 293 | |||
| 294 | 6 | Anonyme | namespace tutorial1.composite { |
| 295 | 7 | Anonyme | component CompositeComponent { |
| 296 | 5 | Anonyme | part server: ServerComponentType { |
| 297 | |||
| 298 | } |
||
| 299 | |||
| 300 | 1 | Anonyme | part client: ClientComponentType { |
| 301 | 5 | Anonyme | |
| 302 | } |
||
| 303 | } |
||
| 304 | } |
||
| 305 | 1 | Anonyme | </pre> |
| 306 | 5 | Anonyme | |
| 307 | An error is present in the editor on the _client_ name to express that some required ports of client are not bound. |
||
| 308 | Using the *bind ... to ...* keyword by it: |
||
| 309 | <pre> |
||
| 310 | 6 | Anonyme | namespace tutorial1.composite { |
| 311 | 7 | Anonyme | component CompositeComponent { |
| 312 | 5 | Anonyme | part server: ServerComponentType { |
| 313 | |||
| 314 | 1 | Anonyme | } |
| 315 | |||
| 316 | part client: ClientComponentType { |
||
| 317 | bind helper to server.service |
||
| 318 | } |
||
| 319 | } |
||
| 320 | } |
||
| 321 | </pre> |
||
| 322 | |||
| 323 | Save. |
||
| 324 | |||
| 325 | h3. Implementing the Component |
||
| 326 | 6 | Anonyme | |
| 327 | 1 | Anonyme | Create a new Java class in tutorial1.composite.impl named CompositeImpl. |
| 328 | 7 | Anonyme | Edit it so that it extends _CompositeComponent_ and resolve all the errors to generate its complete skeleton: |
| 329 | 6 | Anonyme | <pre> |
| 330 | package tutorial1.composite.impl; |
||
| 331 | |||
| 332 | 7 | Anonyme | import tutorial1.CompositeComponent; |
| 333 | 6 | Anonyme | import tutorial1.client.ClientComponentType; |
| 334 | import tutorial1.server.ServerComponentType; |
||
| 335 | |||
| 336 | 7 | Anonyme | public class CompositeImpl extends CompositeComponent { |
| 337 | 6 | Anonyme | |
| 338 | @Override |
||
| 339 | protected ServerComponentType make_server() { |
||
| 340 | // TODO Auto-generated method stub |
||
| 341 | return null; |
||
| 342 | } |
||
| 343 | |||
| 344 | 1 | Anonyme | @Override |
| 345 | 6 | Anonyme | protected ClientComponentType make_client() { |
| 346 | // TODO Auto-generated method stub |
||
| 347 | return null; |
||
| 348 | } |
||
| 349 | } |
||
| 350 | </pre> |
||
| 351 | |||
| 352 | For the _server_ part, return a new instance of the implementation _ServerImpl_ , and the same for the _client_ part with _ClientImpl_: |
||
| 353 | <pre> |
||
| 354 | 7 | Anonyme | public class CompositeImpl extends CompositeComponent { |
| 355 | 6 | Anonyme | |
| 356 | @Override |
||
| 357 | protected ServerComponentType make_server() { |
||
| 358 | return new ServerImpl(); |
||
| 359 | } |
||
| 360 | |||
| 361 | @Override |
||
| 362 | protected ClientComponentType make_client() { |
||
| 363 | return new ClientImpl(); |
||
| 364 | } |
||
| 365 | } |
||
| 366 | 1 | Anonyme | </pre> |
| 367 | 6 | Anonyme | |
| 368 | h3. Creating an Application |
||
| 369 | |||
| 370 | We can now instantiate this composition in an application. |
||
| 371 | 1 | Anonyme | Create a Java class named _Application_ in _tutorial1_ with a *static void main()* method. |
| 372 | 6 | Anonyme | |
| 373 | Create an instance of the composite component in it: |
||
| 374 | <pre> |
||
| 375 | package tutorial1; |
||
| 376 | |||
| 377 | 7 | Anonyme | import tutorial1.composite.CompositeComponent; |
| 378 | 6 | Anonyme | import tutorial1.composite.impl.CompositeImpl; |
| 379 | |||
| 380 | public class Application { |
||
| 381 | |||
| 382 | public static void main(String[] args) { |
||
| 383 | 7 | Anonyme | CompositeComponent.Component component = new CompositeImpl().newComponent(); |
| 384 | 6 | Anonyme | } |
| 385 | |||
| 386 | } |
||
| 387 | </pre> |
||
| 388 | |||
| 389 | 1 | Anonyme | Unfortunately, we forgot to provide a port on this component: it is thus impossible for us to access to the client component inside. |
| 390 | 6 | Anonyme | |
| 391 | h3. Adding a Delegating Port |
||
| 392 | |||
| 393 | In order to be able to use the composite component from Java, we thus need a provided port, and it will delegate to the provided port of the client component. |
||
| 394 | Edit the SpeADL file _composite.speadl_ to add such a delegation: |
||
| 395 | <pre> |
||
| 396 | import tutorial1.client.ClientComponentType |
||
| 397 | import tutorial1.client.interfaces.ASupeNiceService |
||
| 398 | import tutorial1.server.ServerComponentType |
||
| 399 | |||
| 400 | namespace tutorial1.composite { |
||
| 401 | |||
| 402 | 7 | Anonyme | component CompositeComponent { |
| 403 | 6 | Anonyme | |
| 404 | provides service: ASupeNiceService = client.service |
||
| 405 | |||
| 406 | part server: ServerComponentType { |
||
| 407 | |||
| 408 | } |
||
| 409 | |||
| 410 | part client: ClientComponentType { |
||
| 411 | bind helper to server.service |
||
| 412 | 1 | Anonyme | } |
| 413 | 6 | Anonyme | } |
| 414 | } |
||
| 415 | </pre> |
||
| 416 | |||
| 417 | 1 | Anonyme | This is all that is needed for it to work. |
| 418 | 6 | Anonyme | |
| 419 | h3. Running the Application |
||
| 420 | |||
| 421 | Edit the Application class to call the newly added port: |
||
| 422 | <pre> |
||
| 423 | package tutorial1; |
||
| 424 | |||
| 425 | import tutorial1.client.datatypes.Request; |
||
| 426 | 7 | Anonyme | import tutorial1.composite.CompositeComponent; |
| 427 | 6 | Anonyme | import tutorial1.composite.impl.CompositeImpl; |
| 428 | |||
| 429 | 1 | Anonyme | public class Application { |
| 430 | |||
| 431 | public static void main(String[] args) { |
||
| 432 | 7 | Anonyme | CompositeComponent.Component component = new CompositeImpl().newComponent(); |
| 433 | 1 | Anonyme | Request input = new Request(true); |
| 434 | Request output = component.service().compute(input); |
||
| 435 | System.out.println(output.b); |
||
| 436 | } |
||
| 437 | |||
| 438 | } |
||
| 439 | </pre> |
||
| 440 | |||
| 441 | Right-click on the *main()* method and select *Run As / Java Application*. |
||
| 442 | |||
| 443 | Confirm that *false* is printed in the console as expected. |
||
| 444 | 7 | Anonyme | |
| 445 | h2. A Self-Contained Application |
||
| 446 | |||
| 447 | It can be desired that a composition of component is considered a self-contained application, for example with a GUI to execute the client. |
||
| 448 | We will use that example to illustrate the use of the *start()* method. |
||
| 449 | |||
| 450 | h3. A GUI Component |
||
| 451 | |||
| 452 | First, let's create a GUI component: create a file _gui.speadl_ in the package _tutorial1.gui_ containing the definition of our component: |
||
| 453 | <pre> |
||
| 454 | import tutorial1.client.interfaces.ASupeNiceService |
||
| 455 | |||
| 456 | namespace tutorial1.gui { |
||
| 457 | component GUIComponent { |
||
| 458 | requires service: ASupeNiceService |
||
| 459 | } |
||
| 460 | } |
||
| 461 | </pre> |
||
| 462 | |||
| 463 | h3. Component Implementation |
||
| 464 | |||
| 465 | Then the implementation _GUIImpl_ in Java in the package _tutorial1.gui.impl_ exploiting the required port: |
||
| 466 | <pre> |
||
| 467 | package tutorial1.gui.impl; |
||
| 468 | |||
| 469 | import java.awt.BorderLayout; |
||
| 470 | import java.awt.GridLayout; |
||
| 471 | import java.awt.event.ActionEvent; |
||
| 472 | import java.awt.event.ActionListener; |
||
| 473 | |||
| 474 | import javax.swing.JButton; |
||
| 475 | import javax.swing.JCheckBox; |
||
| 476 | import javax.swing.JFrame; |
||
| 477 | import javax.swing.JLabel; |
||
| 478 | import javax.swing.JPanel; |
||
| 479 | import javax.swing.JTextField; |
||
| 480 | |||
| 481 | import tutorial1.client.datatypes.Request; |
||
| 482 | import tutorial1.gui.GUIComponent; |
||
| 483 | |||
| 484 | public class GUIIMpl extends GUIComponent { |
||
| 485 | |||
| 486 | @Override |
||
| 487 | protected void start() { |
||
| 488 | final JFrame f = new JFrame(); |
||
| 489 | final JPanel pnl = new JPanel(new GridLayout(3,2)); |
||
| 490 | pnl.add(new JLabel("Input True? ")); |
||
| 491 | final JCheckBox tf = new JCheckBox(); |
||
| 492 | pnl.add(tf); |
||
| 493 | pnl.add(new JLabel("Output: ")); |
||
| 494 | final JTextField tf2 = new JTextField(5); |
||
| 495 | tf2.setEditable(false); |
||
| 496 | pnl.add(tf2); |
||
| 497 | final JButton bt = new JButton("Compute!"); |
||
| 498 | bt.addActionListener(new ActionListener() { |
||
| 499 | @Override |
||
| 500 | public void actionPerformed(ActionEvent e) { |
||
| 501 | Request res = requires().service().compute(new Request(tf.isSelected())); |
||
| 502 | tf2.setText(""+res.b); |
||
| 503 | } |
||
| 504 | }); |
||
| 505 | pnl.add(bt); |
||
| 506 | f.getContentPane().add(BorderLayout.NORTH, pnl); |
||
| 507 | f.pack(); |
||
| 508 | f.setVisible(true); |
||
| 509 | } |
||
| 510 | } |
||
| 511 | </pre> |
||
| 512 | |||
| 513 | h3. Composite Implementation |
||
| 514 | |||
| 515 | 8 | Anonyme | We will now create a component named _CompositeGUIComponent_ similar to _CompositeComponent_ to use this new component. |
| 516 | 7 | Anonyme | <pre> |
| 517 | import tutorial1.client.ClientComponentType |
||
| 518 | import tutorial1.gui.GUIComponent |
||
| 519 | 1 | Anonyme | import tutorial1.server.ServerComponentType |
| 520 | |||
| 521 | 8 | Anonyme | namespace tutorial1.compositegui { |
| 522 | 7 | Anonyme | |
| 523 | 8 | Anonyme | component CompositeGUIComponent { |
| 524 | 7 | Anonyme | |
| 525 | part server: ServerComponentType |
||
| 526 | |||
| 527 | part client: ClientComponentType { |
||
| 528 | bind helper to server.service |
||
| 529 | } |
||
| 530 | |||
| 531 | part gui: GUIComponent { |
||
| 532 | bind service to client.service |
||
| 533 | } |
||
| 534 | 1 | Anonyme | } |
| 535 | } |
||
| 536 | </pre> |
||
| 537 | |||
| 538 | 8 | Anonyme | Create an implementation _CompositeGUIImpl_: |
| 539 | 1 | Anonyme | <pre> |
| 540 | 8 | Anonyme | package tutorial1.compositegui.impl; |
| 541 | 1 | Anonyme | |
| 542 | 8 | Anonyme | import tutorial1.client.ClientComponentType; |
| 543 | import tutorial1.client.impl.ClientImpl; |
||
| 544 | import tutorial1.compositegui.CompositeGUIComponent; |
||
| 545 | import tutorial1.gui.GUIComponent; |
||
| 546 | import tutorial1.gui.impl.GUIIMpl; |
||
| 547 | import tutorial1.server.ServerComponentType; |
||
| 548 | import tutorial1.server.impl.ServerImpl; |
||
| 549 | |||
| 550 | public class CompositeGUIImpl extends CompositeGUIComponent { |
||
| 551 | |||
| 552 | 7 | Anonyme | @Override |
| 553 | protected ServerComponentType make_server() { |
||
| 554 | return new ServerImpl(); |
||
| 555 | } |
||
| 556 | |||
| 557 | @Override |
||
| 558 | protected ClientComponentType make_client() { |
||
| 559 | return new ClientImpl(); |
||
| 560 | } |
||
| 561 | 1 | Anonyme | |
| 562 | 7 | Anonyme | @Override |
| 563 | 1 | Anonyme | protected GUIComponent make_gui() { |
| 564 | 7 | Anonyme | return new GUIIMpl(); |
| 565 | } |
||
| 566 | 1 | Anonyme | } |
| 567 | 8 | Anonyme | |
| 568 | 7 | Anonyme | </pre> |
| 569 | 1 | Anonyme | |
| 570 | 8 | Anonyme | And the _Application2_ class: |
| 571 | 1 | Anonyme | <pre> |
| 572 | 7 | Anonyme | package tutorial1; |
| 573 | 1 | Anonyme | |
| 574 | 8 | Anonyme | import tutorial1.compositegui.impl.CompositeGUIImpl; |
| 575 | 7 | Anonyme | |
| 576 | 8 | Anonyme | public class Application2 { |
| 577 | 7 | Anonyme | |
| 578 | public static void main(String[] args) { |
||
| 579 | 8 | Anonyme | new CompositeGUIImpl().newComponent(); |
| 580 | 7 | Anonyme | } |
| 581 | 8 | Anonyme | |
| 582 | 7 | Anonyme | } |
| 583 | 8 | Anonyme | |
| 584 | 7 | Anonyme | </pre> |
| 585 | |||
| 586 | And finally run it to test the GUI. |
||
| 587 | Confirm that when the chekbox is checked, compute fill the the output field with false, and the inverse. |
||
| 588 | |||
| 589 | h2. Conclusion |
||
| 590 | |||
| 591 | The tutorial for SpeADL⁻ finishes here. |