Projet

Général

Profil

SpeADL Minus Tutorial » Historique » Version 20

Anonyme, 03/04/2020 01:45
s/Supe/Super/; s/ComponentType/Type/; s/ServiceType/Service/; s/CompositeComponent/CompositeType/

1 12 Anonyme
h1. SpeADL⁻ Tutorial
2 1 Anonyme
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 19 Frédéric Migeon
A Java Application will be created to show how to execute the composition from Java.
16 7 Anonyme
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 17 Anonyme
This procedure is described on [[MAY Install|this page]].
21 1 Anonyme
22
h2. Creating a New Project
23
24
First, we must create a project to work.
25
26 18 Anonyme
In Eclipse, go to the menus : *File / New / Java Project*.
27 1 Anonyme
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 11 Anonyme
Create the following hierarchy of packages (See [[MAY Best Practices#Project Organisation|this best practice]] for details on the matter):
37 1 Anonyme
* _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 20 Anonyme
	component ServerType {
51 1 Anonyme
		
52 3 Anonyme
	}
53
}
54
</pre>
55
56 20 Anonyme
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 _ServerType_.
57 3 Anonyme
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 20 Anonyme
	component ServerType {
66
		provides service: NotSoNiceService
67 3 Anonyme
	}
68
}
69
</pre>
70
71 20 Anonyme
Because the _NotSoNiceService_ interface does not yet exist, there is an error in the SpeADL editor.
72 3 Anonyme
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 20 Anonyme
public interface NotSoNiceService {
79 3 Anonyme
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 20 Anonyme
Create a new Java class in _tutorial1.server.impl_ named ServerImpl, and edit it so that it extends ServerType:
91 3 Anonyme
<pre>
92 20 Anonyme
public class ServerImpl extends ServerType {
93 3 Anonyme
94
}
95
</pre>
96
97 20 Anonyme
Notice that completion can be exploited as _ServerType_ is an actual Java type, but that calling *F3* on it redirects directly to the SpeADL file.
98 3 Anonyme
99 20 Anonyme
Because there is abstract method to implement in _ServerType_, there is errors in the Java editor.
100 3 Anonyme
Use the Quick Fix *Add unimplemented methods* by hovering on the error on the class name _ServerImpl_:
101
<pre>
102 20 Anonyme
public class ServerImpl extends ServerType {
103 3 Anonyme
104
	@Override
105 20 Anonyme
	protected NotSoNiceService make_service() {
106 3 Anonyme
		// TODO Auto-generated method stub
107
		return null;
108
	}
109
110
}
111
</pre>
112
113 20 Anonyme
Remove the *TODO* line and replace _null_ with _new NotSoNiceService_, call completion (*Ctrl+Space*) and choose *NotSoNiceService() Anonymous Inner Type*:
114 3 Anonyme
<pre>
115 20 Anonyme
public class ServerImpl extends ServerType {
116 3 Anonyme
117
	@Override
118 20 Anonyme
	protected NotSoNiceService make_service() {
119
		return new NotSoNiceService() {
120 3 Anonyme
			
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 20 Anonyme
import tutorial1.server.ServerType;
136
import tutorial1.server.interfaces.NotSoNiceService;
137 4 Anonyme
138 20 Anonyme
public class ServerImpl extends ServerType {
139 4 Anonyme
140
	@Override
141 20 Anonyme
	protected NotSoNiceService make_service() {
142
		return new NotSoNiceService() {
143 4 Anonyme
			
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 20 Anonyme
	component ClientType {
172 4 Anonyme
		
173
	}
174
}
175
</pre>
176
177 20 Anonyme
Save and confirm that the *speadl-gen* folder contains a Java class generated in the package _tutorial1.client_ named _ClientType_.
178 4 Anonyme
179
h3. Defining the Ports, their Interfaces and Datatypes
180
181 20 Anonyme
The Client component will provides a port computing a request and will need the _NotSoNiceService_ to do its job:
182 4 Anonyme
<pre>
183 20 Anonyme
import tutorial1.server.interfaces.NotSoNiceService
184 4 Anonyme
185
namespace tutorial1.client {
186
	
187 20 Anonyme
	component ClientType {
188
		provides service: ASuperNiceService
189
		requires helper: NotSoNiceService
190 4 Anonyme
	}
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 20 Anonyme
As before, an error appears in the editor because _ASuperNiceService_ does not exists, create it in _tutorial1.client.interfaces_:
198 4 Anonyme
<pre>
199
package tutorial1.client.interfaces;
200
201 20 Anonyme
public interface ASuperNiceService {
202 4 Anonyme
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 20 Anonyme
Edit it so that it extends _ClientType_ and resolve all the errors to generate its complete skeleton:
227 5 Anonyme
<pre>
228
package tutorial1.client.impl;
229
230 20 Anonyme
import tutorial1.client.ClientType;
231 5 Anonyme
import tutorial1.client.datatypes.Request;
232 20 Anonyme
import tutorial1.client.interfaces.ASuperNiceService;
233 5 Anonyme
234 20 Anonyme
public class ClientImpl extends ClientType {
235 5 Anonyme
236
	@Override
237 20 Anonyme
	protected ASuperNiceService make_service() {
238
		return new ASuperNiceService() {
239 5 Anonyme
			
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 20 Anonyme
public class ClientImpl extends ClientType {
254 5 Anonyme
255
	@Override
256 20 Anonyme
	protected ASuperNiceService make_service() {
257
		return new ASuperNiceService() {
258 5 Anonyme
			@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 20 Anonyme
Define the namespace we are going to work in as well as the _CompositeType_ component:
277 5 Anonyme
<pre>
278 6 Anonyme
namespace tutorial1.composite {
279 20 Anonyme
	component CompositeType {
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 20 Anonyme
In CompositeType, 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 20 Anonyme
import tutorial1.client.ClientType
293
import tutorial1.server.ServerType
294 5 Anonyme
295 6 Anonyme
namespace tutorial1.composite {
296 20 Anonyme
	component CompositeType {
297
		part server: ServerType {
298 5 Anonyme
			
299
		}
300
		
301 20 Anonyme
		part client: ClientType {
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 20 Anonyme
	component CompositeType {
313
		part server: ServerType {
314 5 Anonyme
			
315 1 Anonyme
		}
316
		
317 20 Anonyme
		part client: ClientType {
318 1 Anonyme
			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 20 Anonyme
Edit it so that it extends _CompositeType_ and resolve all the errors to generate its complete skeleton:
330 6 Anonyme
<pre>
331
package tutorial1.composite.impl;
332
333 20 Anonyme
import tutorial1.CompositeType;
334
import tutorial1.client.ClientType;
335
import tutorial1.server.ServerType;
336 6 Anonyme
337 20 Anonyme
public class CompositeImpl extends CompositeType {
338 6 Anonyme
339
	@Override
340 20 Anonyme
	protected ServerType make_server() {
341 6 Anonyme
		// TODO Auto-generated method stub
342
		return null;
343
	}
344
345 1 Anonyme
	@Override
346 20 Anonyme
	protected ClientType make_client() {
347 6 Anonyme
		// 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 20 Anonyme
public class CompositeImpl extends CompositeType {
356 6 Anonyme
357
	@Override
358 20 Anonyme
	protected ServerType make_server() {
359 6 Anonyme
		return new ServerImpl();
360
	}
361
362
	@Override
363 20 Anonyme
	protected ClientType make_client() {
364 6 Anonyme
		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 20 Anonyme
import tutorial1.composite.CompositeType;
379 6 Anonyme
import tutorial1.composite.impl.CompositeImpl;
380
381
public class Application {
382
383
	public static void main(String[] args) {
384 20 Anonyme
		CompositeType.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 20 Anonyme
import tutorial1.client.ClientType
398
import tutorial1.client.interfaces.ASuperNiceService
399
import tutorial1.server.ServerType
400 6 Anonyme
401
namespace tutorial1.composite {
402
	
403 20 Anonyme
	component CompositeType {
404 6 Anonyme
		
405 20 Anonyme
		provides service: ASuperNiceService = client.service
406 6 Anonyme
		
407 20 Anonyme
		part server: ServerType {
408 6 Anonyme
			
409
		}
410
		
411 20 Anonyme
		part client: ClientType {
412 6 Anonyme
			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 20 Anonyme
import tutorial1.composite.CompositeType;
428 6 Anonyme
import tutorial1.composite.impl.CompositeImpl;
429
430 1 Anonyme
public class Application {
431
432
	public static void main(String[] args) {
433 20 Anonyme
		CompositeType.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 18 Anonyme
h3. A GUI Component
452 7 Anonyme
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 20 Anonyme
import tutorial1.client.interfaces.ASuperNiceService
456 7 Anonyme
457
namespace tutorial1.gui {
458
	component GUIComponent {
459 20 Anonyme
		requires service: ASuperNiceService
460 7 Anonyme
	}	
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 13 Anonyme
import javax.swing.SwingUtilities;
482 7 Anonyme
483
import tutorial1.client.datatypes.Request;
484
import tutorial1.gui.GUIComponent;
485
486 18 Anonyme
public class GUIImpl extends GUIComponent {
487 7 Anonyme
488
	@Override
489 1 Anonyme
	protected void start() {
490 13 Anonyme
		SwingUtilities.invokeLater(new Runnable() {
491 1 Anonyme
			@Override
492 13 Anonyme
			public void run() {
493
				final JFrame f = new JFrame();
494
				final JPanel pnl = new JPanel(new GridLayout(3,2));
495
			    pnl.add(new JLabel("Input True? "));
496
			    final JCheckBox tf = new JCheckBox();
497
			    pnl.add(tf);
498
			    pnl.add(new JLabel("Output: "));
499
			    final JTextField tf2 = new JTextField(5);
500
			    tf2.setEditable(false);
501
			    pnl.add(tf2);
502
			    final JButton bt = new JButton("Compute!");
503
			    bt.addActionListener(new ActionListener() {
504
					@Override
505
					public void actionPerformed(ActionEvent e) {
506
						Request res = requires().service().compute(new Request(tf.isSelected()));
507
						tf2.setText(""+res.b);
508
					}
509
				});
510
			    pnl.add(bt);
511
			    f.getContentPane().add(BorderLayout.NORTH, pnl);
512
			    f.pack();
513
			    f.setVisible(true);
514 14 Anonyme
			    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
515 7 Anonyme
			}
516
		});
517
	}
518
}
519
</pre>
520
521
h3. Composite Implementation
522
523 20 Anonyme
We will now create a component named _CompositeGUIComponent_ similar to _CompositeType_ to use this new component.
524 7 Anonyme
<pre>
525 20 Anonyme
import tutorial1.client.ClientType
526 7 Anonyme
import tutorial1.gui.GUIComponent
527 20 Anonyme
import tutorial1.server.ServerType
528 1 Anonyme
529 8 Anonyme
namespace tutorial1.compositegui {
530 7 Anonyme
	
531 8 Anonyme
	component CompositeGUIComponent {
532 7 Anonyme
		
533 20 Anonyme
		part server: ServerType
534 7 Anonyme
		
535 20 Anonyme
		part client: ClientType {
536 7 Anonyme
			bind helper to server.service
537
		}
538
		
539
		part gui: GUIComponent {
540
			bind service to client.service
541
		}
542 1 Anonyme
	}
543
}
544
</pre>
545
546 8 Anonyme
Create an implementation _CompositeGUIImpl_:
547 1 Anonyme
<pre>
548 8 Anonyme
package tutorial1.compositegui.impl;
549 1 Anonyme
550 20 Anonyme
import tutorial1.client.ClientType;
551 8 Anonyme
import tutorial1.client.impl.ClientImpl;
552
import tutorial1.compositegui.CompositeGUIComponent;
553
import tutorial1.gui.GUIComponent;
554 18 Anonyme
import tutorial1.gui.impl.GUIImpl;
555 20 Anonyme
import tutorial1.server.ServerType;
556 8 Anonyme
import tutorial1.server.impl.ServerImpl;
557
558
public class CompositeGUIImpl extends CompositeGUIComponent {
559
560 7 Anonyme
	@Override
561 20 Anonyme
	protected ServerType make_server() {
562 7 Anonyme
		return new ServerImpl();
563
	}
564
565
	@Override
566 20 Anonyme
	protected ClientType make_client() {
567 7 Anonyme
		return new ClientImpl();
568
	}
569 1 Anonyme
570 7 Anonyme
	@Override
571 1 Anonyme
	protected GUIComponent make_gui() {
572 18 Anonyme
		return new GUIImpl();
573 7 Anonyme
	}
574 1 Anonyme
}
575 8 Anonyme
576 7 Anonyme
</pre>
577 1 Anonyme
578 8 Anonyme
And the _Application2_ class:
579 1 Anonyme
<pre>
580 7 Anonyme
package tutorial1;
581 1 Anonyme
582 8 Anonyme
import tutorial1.compositegui.impl.CompositeGUIImpl;
583 7 Anonyme
584 8 Anonyme
public class Application2 {
585 7 Anonyme
586
	public static void main(String[] args) {
587 8 Anonyme
		new CompositeGUIImpl().newComponent();
588 7 Anonyme
	}
589 8 Anonyme
590 7 Anonyme
}
591 8 Anonyme
592 7 Anonyme
</pre>
593
594
And finally run it to test the GUI.
595
Confirm that when the chekbox is checked, compute fill the the output field with false, and the inverse.
596
597
h2. Conclusion
598
599 15 Anonyme
This tutorial for SpeADL⁻ finishes here.
600 9 Anonyme
601
h1. Wiki Page Resources