Projet

Général

Profil

SpeADL Minus Tutorial » Historique » Version 15

Anonyme, 15/10/2014 10:39

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 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 10 Anonyme
This procedure is described on [[MAY Project Setup|this page]].
21 1 Anonyme
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 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
	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 13 Anonyme
import javax.swing.SwingUtilities;
482 7 Anonyme
483
import tutorial1.client.datatypes.Request;
484
import tutorial1.gui.GUIComponent;
485
486
public class GUIIMpl extends GUIComponent {
487
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 8 Anonyme
We will now create a component named _CompositeGUIComponent_ similar to _CompositeComponent_ to use this new component.
524 7 Anonyme
<pre>
525
import tutorial1.client.ClientComponentType
526
import tutorial1.gui.GUIComponent
527 1 Anonyme
import tutorial1.server.ServerComponentType
528
529 8 Anonyme
namespace tutorial1.compositegui {
530 7 Anonyme
	
531 8 Anonyme
	component CompositeGUIComponent {
532 7 Anonyme
		
533
		part server: ServerComponentType
534
		
535
		part client: ClientComponentType {
536
			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 8 Anonyme
import tutorial1.client.ClientComponentType;
551
import tutorial1.client.impl.ClientImpl;
552
import tutorial1.compositegui.CompositeGUIComponent;
553
import tutorial1.gui.GUIComponent;
554
import tutorial1.gui.impl.GUIIMpl;
555
import tutorial1.server.ServerComponentType;
556
import tutorial1.server.impl.ServerImpl;
557
558
public class CompositeGUIImpl extends CompositeGUIComponent {
559
560 7 Anonyme
	@Override
561
	protected ServerComponentType make_server() {
562
		return new ServerImpl();
563
	}
564
565
	@Override
566
	protected ClientComponentType make_client() {
567
		return new ClientImpl();
568
	}
569 1 Anonyme
570 7 Anonyme
	@Override
571 1 Anonyme
	protected GUIComponent make_gui() {
572 7 Anonyme
		return new GUIIMpl();
573
	}
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