SpeADL Minus Tutorial » Historique » Version 6
Anonyme, 06/10/2014 16:13
| 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 | 6 | Anonyme | A Java *main()* will be created to show how to execute the composition from Java. |
| 15 | 1 | Anonyme | |
| 16 | h2. Installing Eclipse and MAY |
||
| 17 | |||
| 18 | This procedure is described on [[SpeADL MAY Project SetUp|this page]]. |
||
| 19 | |||
| 20 | h2. Creating a New Project |
||
| 21 | |||
| 22 | First, we must create a project to work. |
||
| 23 | |||
| 24 | In Eclipse, go to the menus : *File / New / Java Project*. |
||
| 25 | |||
| 26 | Enter _Tutorial 1_ as the project name, verify that the *execution environment JRE* is 1.5 or above. |
||
| 27 | |||
| 28 | As a start, create a package in the *src* folder called _tutorial1_. |
||
| 29 | |||
| 30 | h2. The Server Component |
||
| 31 | |||
| 32 | 3 | Anonyme | h3. Organisation |
| 33 | |||
| 34 | 1 | Anonyme | Create the following hierarchy of packages (See [[SpeADL Best Practices#Project Organisation|this best practice]] for details on the matter): |
| 35 | * _tutorial1.server_ |
||
| 36 | ** _impl_ |
||
| 37 | ** _interfaces_ |
||
| 38 | |||
| 39 | 3 | Anonyme | h3. Defining the Component |
| 40 | |||
| 41 | 2 | Anonyme | Create a SpeADL file: |
| 42 | * Right-click on tutorial1.server and select *New / File*. |
||
| 43 | * Enter _server.speadl_ as the file name. |
||
| 44 | 1 | Anonyme | |
| 45 | Define the namespace we are going to work in as well as the _Server_ component: |
||
| 46 | <pre> |
||
| 47 | namespace tutorial1.server { |
||
| 48 | component ServerComponentType { |
||
| 49 | |||
| 50 | 3 | Anonyme | } |
| 51 | } |
||
| 52 | </pre> |
||
| 53 | |||
| 54 | 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_. |
||
| 55 | |||
| 56 | h3. Defining a Port and its Interface |
||
| 57 | |||
| 58 | The _Server_ component will provide a port whose interface contains one method to give the contrary of a boolean. |
||
| 59 | |||
| 60 | Add it to the component declaration: |
||
| 61 | <pre> |
||
| 62 | namespace tutorial1.server { |
||
| 63 | component ServerComponentType { |
||
| 64 | provides service: NotSoNiceServiceType |
||
| 65 | } |
||
| 66 | } |
||
| 67 | </pre> |
||
| 68 | |||
| 69 | Because the _NotSoNiceServiceType_ interface does not yet exist, there is an error in the SpeADL editor. |
||
| 70 | We will store the interface in the _tutorial1.server.interfaces_ package. |
||
| 71 | |||
| 72 | Either create it by hand or use the Quick Fix proposed by SpeADL editor by hovering on the error. |
||
| 73 | <pre> |
||
| 74 | package tutorial1.server.interfaces; |
||
| 75 | |||
| 76 | public interface NotSoNiceServiceType { |
||
| 77 | |||
| 78 | public boolean contrary(boolean b); |
||
| 79 | } |
||
| 80 | </pre> |
||
| 81 | |||
| 82 | Save, and go back to the SpeADL editor for _server.speadl_. |
||
| 83 | Call the automatic import organiser with *Ctrl+Shift+O*. |
||
| 84 | Confirm that an import was added on top of the SpeADL file and save. |
||
| 85 | |||
| 86 | h3. Implementing the Component |
||
| 87 | |||
| 88 | Create a new Java class in _tutorial1.server.impl_ named ServerImpl, and edit it so that it extends ServerComponentType: |
||
| 89 | <pre> |
||
| 90 | 5 | Anonyme | public class ServerImpl extends ServerComponentType { |
| 91 | 3 | Anonyme | |
| 92 | } |
||
| 93 | </pre> |
||
| 94 | |||
| 95 | 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. |
||
| 96 | |||
| 97 | Because there is abstract method to implement in _ServerComponentType_, there is errors in the Java editor. |
||
| 98 | Use the Quick Fix *Add unimplemented methods* by hovering on the error on the class name _ServerImpl_: |
||
| 99 | <pre> |
||
| 100 | public class ServerImpl extends ServerComponentType { |
||
| 101 | |||
| 102 | @Override |
||
| 103 | protected NotSoNiceServiceType make_service() { |
||
| 104 | // TODO Auto-generated method stub |
||
| 105 | return null; |
||
| 106 | } |
||
| 107 | |||
| 108 | } |
||
| 109 | </pre> |
||
| 110 | |||
| 111 | Remove the *TODO* line and replace _null_ with _new NotSoNiceServiceType_, call completion (*Ctrl+Space*) and choose *NotSoNiceServiceType() Anonymous Inner Type*: |
||
| 112 | <pre> |
||
| 113 | public class ServerImpl extends ServerComponentType { |
||
| 114 | |||
| 115 | @Override |
||
| 116 | protected NotSoNiceServiceType make_service() { |
||
| 117 | return new NotSoNiceServiceType() { |
||
| 118 | |||
| 119 | @Override |
||
| 120 | public boolean contrary(boolean b) { |
||
| 121 | // TODO Auto-generated method stub |
||
| 122 | return false; |
||
| 123 | 1 | Anonyme | } |
| 124 | }; |
||
| 125 | 4 | Anonyme | } |
| 126 | } |
||
| 127 | </pre> |
||
| 128 | |||
| 129 | Remove the *TODO* line and replace _return false;_ by _return !b;_: |
||
| 130 | <pre> |
||
| 131 | package tutorial1.server.impl; |
||
| 132 | |||
| 133 | import tutorial1.server.ServerComponentType; |
||
| 134 | import tutorial1.server.interfaces.NotSoNiceServiceType; |
||
| 135 | |||
| 136 | public class ServerImpl extends ServerComponentType { |
||
| 137 | |||
| 138 | @Override |
||
| 139 | protected NotSoNiceServiceType make_service() { |
||
| 140 | return new NotSoNiceServiceType() { |
||
| 141 | |||
| 142 | @Override |
||
| 143 | public boolean contrary(boolean b) { |
||
| 144 | return !b; |
||
| 145 | } |
||
| 146 | }; |
||
| 147 | } |
||
| 148 | |||
| 149 | } |
||
| 150 | </pre> |
||
| 151 | |||
| 152 | 1 | Anonyme | h2. The Client Component |
| 153 | 4 | Anonyme | |
| 154 | h3. Organisation |
||
| 155 | |||
| 156 | 5 | Anonyme | Create the following hierarchy of packages: |
| 157 | 4 | Anonyme | * _tutorial1.client_ |
| 158 | ** _impl_ |
||
| 159 | ** _interfaces_ |
||
| 160 | ** _datatypes_ |
||
| 161 | |||
| 162 | h3. Defining the Component |
||
| 163 | |||
| 164 | Create a SpeADL file in _tutorial1.client_ named _client.speadl_. |
||
| 165 | |||
| 166 | Define the namespace we are going to work in as well as the _Client_ component: |
||
| 167 | <pre> |
||
| 168 | namespace tutorial1.client { |
||
| 169 | component ClientComponentType { |
||
| 170 | |||
| 171 | } |
||
| 172 | } |
||
| 173 | </pre> |
||
| 174 | |||
| 175 | Save and confirm that the *speadl-gen* folder contains a Java class generated in the package _tutorial1.client_ named _ClientComponentType_. |
||
| 176 | |||
| 177 | h3. Defining the Ports, their Interfaces and Datatypes |
||
| 178 | |||
| 179 | The Client component will provides a port computing a request and will need the _NotSoNiceServiceType_ to do its job: |
||
| 180 | <pre> |
||
| 181 | import tutorial1.server.interfaces.NotSoNiceServiceType |
||
| 182 | |||
| 183 | namespace tutorial1.client { |
||
| 184 | |||
| 185 | component ClientComponentType { |
||
| 186 | provides service: ASupeNiceService |
||
| 187 | requires helper: NotSoNiceServiceType |
||
| 188 | } |
||
| 189 | |||
| 190 | } |
||
| 191 | </pre> |
||
| 192 | |||
| 193 | Don't hesitate to exploit completion (*Ctrl+Space*) and automatic import organiser (*Ctrl+Shift+O*) to type the interfaces names. |
||
| 194 | |||
| 195 | As before, an error appears in the editor because _ASupeNiceService_ does not exists, create it in _tutorial1.client.interfaces_: |
||
| 196 | <pre> |
||
| 197 | package tutorial1.client.interfaces; |
||
| 198 | |||
| 199 | public interface ASupeNiceService { |
||
| 200 | |||
| 201 | 1 | Anonyme | public Request compute(Request r); |
| 202 | |||
| 203 | 4 | Anonyme | } |
| 204 | </pre> |
||
| 205 | |||
| 206 | 5 | Anonyme | As we can see, we rely on a type named _Request_. |
| 207 | Create it in _tutorial1.client.datatypes_: |
||
| 208 | 4 | Anonyme | <pre> |
| 209 | package tutorial1.client.datatypes; |
||
| 210 | |||
| 211 | public class Request { |
||
| 212 | |||
| 213 | public final boolean b; |
||
| 214 | 1 | Anonyme | |
| 215 | public Request(boolean b) { |
||
| 216 | this.b = b; |
||
| 217 | } |
||
| 218 | } |
||
| 219 | </pre> |
||
| 220 | 5 | Anonyme | |
| 221 | h3. Implementing the Component |
||
| 222 | |||
| 223 | Create a new Java class in tutorial1.client.impl named ClientImpl. |
||
| 224 | Edit it so that it extends _ClientComponentType_ and resolve all the errors to generate its complete skeleton: |
||
| 225 | <pre> |
||
| 226 | package tutorial1.client.impl; |
||
| 227 | |||
| 228 | import tutorial1.client.ClientComponentType; |
||
| 229 | import tutorial1.client.datatypes.Request; |
||
| 230 | import tutorial1.client.interfaces.ASupeNiceService; |
||
| 231 | |||
| 232 | public class ClientImpl extends ClientComponentType { |
||
| 233 | |||
| 234 | @Override |
||
| 235 | protected ASupeNiceService make_service() { |
||
| 236 | return new ASupeNiceService() { |
||
| 237 | |||
| 238 | @Override |
||
| 239 | public Request compute(Request r) { |
||
| 240 | // TODO Auto-generated method stub |
||
| 241 | return null; |
||
| 242 | } |
||
| 243 | }; |
||
| 244 | } |
||
| 245 | |||
| 246 | } |
||
| 247 | </pre> |
||
| 248 | |||
| 249 | Implement the _compute()_ method to call the required port _helper_ to actually do the computation and to return a new _Request_: |
||
| 250 | <pre> |
||
| 251 | public class ClientImpl extends ClientComponentType { |
||
| 252 | |||
| 253 | @Override |
||
| 254 | protected ASupeNiceService make_service() { |
||
| 255 | return new ASupeNiceService() { |
||
| 256 | @Override |
||
| 257 | public Request compute(Request r) { |
||
| 258 | final boolean contrary = requires().helper().contrary(r.b); |
||
| 259 | return new Request(contrary); |
||
| 260 | } |
||
| 261 | }; |
||
| 262 | } |
||
| 263 | } |
||
| 264 | </pre> |
||
| 265 | |||
| 266 | h2. The Composite Component |
||
| 267 | |||
| 268 | In order to use the Client and the Server components together, we need to build a composite component connecting them together. |
||
| 269 | |||
| 270 | 1 | Anonyme | h3. Defining the Component |
| 271 | |||
| 272 | 6 | Anonyme | Create a SpeADL file in _tutorial1.composite_ named _composite.speadl_. |
| 273 | 5 | Anonyme | |
| 274 | 6 | Anonyme | Define the namespace we are going to work in as well as the _CompositeComponentType_ component: |
| 275 | 5 | Anonyme | <pre> |
| 276 | 6 | Anonyme | namespace tutorial1.composite { |
| 277 | component CompositeComponentType { |
||
| 278 | 5 | Anonyme | |
| 279 | } |
||
| 280 | } |
||
| 281 | 1 | Anonyme | </pre> |
| 282 | 5 | Anonyme | |
| 283 | Save. |
||
| 284 | |||
| 285 | 1 | Anonyme | h3. Defining the Composition |
| 286 | 5 | Anonyme | |
| 287 | 6 | Anonyme | In CompositeComponentType, there will be one server and one client for now. |
| 288 | Declare them as parts in the composite component: |
||
| 289 | 5 | Anonyme | <pre> |
| 290 | import tutorial1.client.ClientComponentType |
||
| 291 | import tutorial1.server.ServerComponentType |
||
| 292 | |||
| 293 | 6 | Anonyme | namespace tutorial1.composite { |
| 294 | component CompositeComponentType { |
||
| 295 | 5 | Anonyme | part server: ServerComponentType { |
| 296 | |||
| 297 | } |
||
| 298 | |||
| 299 | 1 | Anonyme | part client: ClientComponentType { |
| 300 | 5 | Anonyme | |
| 301 | } |
||
| 302 | } |
||
| 303 | } |
||
| 304 | </pre> |
||
| 305 | |||
| 306 | An error is present in the editor on the _client_ name to express that some required ports of client are not bound. |
||
| 307 | Using the *bind ... to ...* keyword by it: |
||
| 308 | <pre> |
||
| 309 | 6 | Anonyme | namespace tutorial1.composite { |
| 310 | component CompositeComponentType { |
||
| 311 | 5 | Anonyme | part server: ServerComponentType { |
| 312 | |||
| 313 | 1 | Anonyme | } |
| 314 | |||
| 315 | part client: ClientComponentType { |
||
| 316 | bind helper to server.service |
||
| 317 | } |
||
| 318 | } |
||
| 319 | } |
||
| 320 | </pre> |
||
| 321 | |||
| 322 | Save. |
||
| 323 | |||
| 324 | h3. Implementing the Component |
||
| 325 | 6 | Anonyme | |
| 326 | Create a new Java class in tutorial1.composite.impl named CompositeImpl. |
||
| 327 | Edit it so that it extends _CompositeComponentType_ and resolve all the errors to generate its complete skeleton: |
||
| 328 | <pre> |
||
| 329 | package tutorial1.composite.impl; |
||
| 330 | |||
| 331 | import tutorial1.CompositeComponentType; |
||
| 332 | import tutorial1.client.ClientComponentType; |
||
| 333 | import tutorial1.server.ServerComponentType; |
||
| 334 | |||
| 335 | public class CompositeImpl extends CompositeComponentType { |
||
| 336 | |||
| 337 | @Override |
||
| 338 | protected ServerComponentType make_server() { |
||
| 339 | // TODO Auto-generated method stub |
||
| 340 | return null; |
||
| 341 | } |
||
| 342 | |||
| 343 | @Override |
||
| 344 | protected ClientComponentType make_client() { |
||
| 345 | // TODO Auto-generated method stub |
||
| 346 | return null; |
||
| 347 | } |
||
| 348 | } |
||
| 349 | </pre> |
||
| 350 | |||
| 351 | For the _server_ part, return a new instance of the implementation _ServerImpl_ , and the same for the _client_ part with _ClientImpl_: |
||
| 352 | <pre> |
||
| 353 | public class CompositeImpl extends CompositeComponentType { |
||
| 354 | |||
| 355 | @Override |
||
| 356 | protected ServerComponentType make_server() { |
||
| 357 | return new ServerImpl(); |
||
| 358 | } |
||
| 359 | |||
| 360 | @Override |
||
| 361 | protected ClientComponentType make_client() { |
||
| 362 | return new ClientImpl(); |
||
| 363 | } |
||
| 364 | } |
||
| 365 | </pre> |
||
| 366 | |||
| 367 | h3. Creating an Application |
||
| 368 | |||
| 369 | We can now instantiate this composition in an application. |
||
| 370 | Create a Java class named _Application_ in _tutorial1_ with a *static void main()* method. |
||
| 371 | |||
| 372 | Create an instance of the composite component in it: |
||
| 373 | <pre> |
||
| 374 | package tutorial1; |
||
| 375 | |||
| 376 | import tutorial1.composite.CompositeComponentType; |
||
| 377 | import tutorial1.composite.impl.CompositeImpl; |
||
| 378 | |||
| 379 | public class Application { |
||
| 380 | |||
| 381 | public static void main(String[] args) { |
||
| 382 | CompositeComponentType.Component component = new CompositeImpl().newComponent(); |
||
| 383 | } |
||
| 384 | |||
| 385 | } |
||
| 386 | </pre> |
||
| 387 | |||
| 388 | Unfortunately, we forgot to provide a port on this component: it is thus impossible for us to access to the client component inside. |
||
| 389 | |||
| 390 | h3. Adding a Delegating Port |
||
| 391 | |||
| 392 | 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. |
||
| 393 | Edit the SpeADL file _composite.speadl_ to add such a delegation: |
||
| 394 | <pre> |
||
| 395 | import tutorial1.client.ClientComponentType |
||
| 396 | import tutorial1.client.interfaces.ASupeNiceService |
||
| 397 | import tutorial1.server.ServerComponentType |
||
| 398 | |||
| 399 | namespace tutorial1.composite { |
||
| 400 | |||
| 401 | component CompositeComponentType { |
||
| 402 | |||
| 403 | provides service: ASupeNiceService = client.service |
||
| 404 | |||
| 405 | part server: ServerComponentType { |
||
| 406 | |||
| 407 | } |
||
| 408 | |||
| 409 | part client: ClientComponentType { |
||
| 410 | bind helper to server.service |
||
| 411 | } |
||
| 412 | } |
||
| 413 | } |
||
| 414 | </pre> |
||
| 415 | |||
| 416 | This is all that is needed for it to work. |
||
| 417 | |||
| 418 | h3. Running the Application |
||
| 419 | |||
| 420 | Edit the Application class to call the newly added port: |
||
| 421 | <pre> |
||
| 422 | package tutorial1; |
||
| 423 | |||
| 424 | import tutorial1.client.datatypes.Request; |
||
| 425 | import tutorial1.composite.CompositeComponentType; |
||
| 426 | import tutorial1.composite.impl.CompositeImpl; |
||
| 427 | |||
| 428 | public class Application { |
||
| 429 | |||
| 430 | public static void main(String[] args) { |
||
| 431 | CompositeComponentType.Component component = new CompositeImpl().newComponent(); |
||
| 432 | Request input = new Request(true); |
||
| 433 | Request output = component.service().compute(input); |
||
| 434 | System.out.println(output.b); |
||
| 435 | } |
||
| 436 | |||
| 437 | } |
||
| 438 | </pre> |
||
| 439 | |||
| 440 | Right-click on the *main()* method and select *Run As / Java Application*. |
||
| 441 | |||
| 442 | Confirm that *false* is printed in the console as expected. |