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