Projet

Général

Profil

SpeADL Minus Tutorial » Historique » Version 7

Anonyme, 06/10/2014 16:40

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
We will now update the existing _CompositeComponent_ declaration to use this new component.
516
Remove the provided port and add the GUI as a part:
517
<pre>
518
import tutorial1.client.ClientComponentType
519
import tutorial1.gui.GUIComponent
520
import tutorial1.server.ServerComponentType
521
522
namespace tutorial1.composite {
523
	
524
	component CompositeComponent {
525
		
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
	}
536
}
537
</pre>
538
539
Update the implementation _CompositeImpl_:
540
<pre>
541
public class CompositeImpl extends CompositeComponent {
542
543
	@Override
544
	protected ServerComponentType make_server() {
545
		return new ServerImpl();
546
	}
547
548
	@Override
549
	protected ClientComponentType make_client() {
550
		return new ClientImpl();
551
	}
552
553
	@Override
554
	protected GUIComponent make_gui() {
555
		return new GUIIMpl();
556
	}
557
}
558
</pre>
559
560
And the _Application_ class:
561
<pre>
562
package tutorial1;
563
564
import tutorial1.composite.impl.CompositeImpl;
565
566
public class Application {
567
568
	public static void main(String[] args) {
569
		new CompositeImpl().newComponent();
570
	}
571
}
572
</pre>
573
574
And finally run it to test the GUI.
575
Confirm that when the chekbox is checked, compute fill the the output field with false, and the inverse.
576
577
h2. Conclusion
578
579
The tutorial for SpeADL⁻ finishes here.