Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 44

Anonyme, 15/10/2014 15:46

1 44 Anonyme
h1. SpeADL⁻ Reference
2 1 Anonyme
3 2 Anonyme
{{>toc}}
4 1 Anonyme
5 44 Anonyme
In SpeADL, a subset of abstractions are provided to define traditional component-oriented architectures.
6
This subset of SpeADL is sometimes called SpeADL⁻ (pronounced SpeADL Minus).
7 33 Anonyme
With it, it is possible to define software components and compositions of components, called composites, implemented in Java, while keeping a strong link between definition and implementation by relying on an Eclipse plugin and automatic code generation.
8 1 Anonyme
9 4 Anonyme
A component is made of two elements: a class definition using SpeADL and an implementation using Java.
10 33 Anonyme
Optionally, the SpeADL definition can contain a bit of implementation in the form of a composition of components connected together.
11 31 Anonyme
From the SpeADL definition, an abstract Java class (which exactly reflects the definition) is automatically generated and then relied upon through the Java extension mechanism to implement what is left in the component in a safe manner.
12 1 Anonyme
13 35 Anonyme
h2. Terminology
14
15
The reader can refer to the [[MAY Terminology]] document to get an overview of the different terms used in SpeADL.
16
17 1 Anonyme
h2. Namespaces
18
19 5 Anonyme
A namespace plays the exact same role as a package in Java.
20
21 4 Anonyme
h3. Keyword
22
23 31 Anonyme
Namespaces are declared using the keyword *namespace*.
24 1 Anonyme
25 4 Anonyme
h3. Details
26
27 1 Anonyme
In a SpeADL file, there can be many as namespace (as well as nested ones) as wanted.
28 31 Anonyme
Hence a namespace does not have to follow the name of the directory it is located (as it is the case in Java).
29 1 Anonyme
30 4 Anonyme
Each namespace declaration can contain any component as desired as we are going to see.
31
32
h3. Example
33
34 1 Anonyme
<pre>
35
namespace simple {
36
37
	namespace things {
38 19 Anonyme
39 1 Anonyme
	}
40
}
41
42 19 Anonyme
namespace simple.things {
43
44
}
45
46 1 Anonyme
namespace simple.stuffs {
47 19 Anonyme
48 1 Anonyme
}
49
</pre>
50
51
h2. Imports
52
53 20 Anonyme
As in Java, it is possible to import existing names to avoid referring to them with their fully qualified name (i.e., including their package or namespace).
54 1 Anonyme
55 5 Anonyme
h3. Keyword and Role
56
57
As in Java, this is done with the keyword *import*.
58
59
h3. Details
60
61
The namespace of components are also considered to import component class definitions.
62
63 33 Anonyme
The imports can be automatically handled and reorganised in Eclipse using the *Ctrl-Shift-O* shortcut as with the Java editor.
64 5 Anonyme
65 33 Anonyme
They are always situated at the top of a SpeADL file.
66 5 Anonyme
67
h3. Example
68
69 1 Anonyme
The syntax is similar to Java:
70
<pre>
71
import java.util.Collection
72
import java.util.*
73
import simple.stuffs.*
74
</pre>
75
76 33 Anonyme
h2. Component Definition
77 1 Anonyme
78 33 Anonyme
A software component is made of a definition and an implementation: an instance can then be created from the implementation.
79
A component definition has provided and required ports, as well as parts which are themselves components.
80 1 Anonyme
A part is structurally similar to a class member in Java.
81 5 Anonyme
For each required port of a part, there must be a binding declaring what is providing the required port.
82 1 Anonyme
83
h3. Keywords
84
85 33 Anonyme
A component definition is declared with the keyword *component* followed by a name starting with a capital letter.
86
It must be unique in its namespace.
87 1 Anonyme
88 43 Frédéric Migeon
The keywords *provides* and *requires* are used to declare, respectively, provided and required ports. They are followed by a name (unique in the component and without capital letter) and an interface name separated by the character *: *.
89 1 Anonyme
It takes the form _provides name: Interface_ or _requires name: Interface_, where _Interface_ is a Java type.
90
91 31 Anonyme
The keyword *part* is used to declare a part in a component.
92 33 Anonyme
It is followed by a name for the part (unique in the component and without capital letter) and a component class definition name separated by the character *: *.
93 31 Anonyme
It takes the form _part name: ComponentName_.
94 5 Anonyme
95 33 Anonyme
For each part, bindings are used to declare for each of its required port what is fulfilling the requirement.
96
It is done using the keywords *bind* and *to* in the form _bind ...1 to ...2_ where _...1_ is the name of the required port of the part and _...2_ is a reference to a port available in the component containing the part.
97 5 Anonyme
Such a reference can either be:
98 31 Anonyme
* To another part's provided port, taking the form _bind req to name.port_.
99
* A provided or a required port of the current containing component, taking the form _bind req to port_.
100 5 Anonyme
101 31 Anonyme
A delegation is used to declare for the provided port of a component what other port will provides its implementation.
102 33 Anonyme
It is done using the keyword * =  * followed by a reference to a port available in the current containing component (as with bindings).
103 31 Anonyme
It takes the form _provides name: Interface = name.port_ or _provides name: Interface = port_.
104 5 Anonyme
105
h3. Details
106
107 31 Anonyme
An interface is understood as a Java interface, i.e., a collection of methods, and must be visible in the classpath of the Java project.
108 5 Anonyme
109 33 Anonyme
All the required of a part must be bound for the component definition to be valid.
110 1 Anonyme
111 5 Anonyme
h3. Example
112
113 6 Anonyme
Component class definitions:
114 1 Anonyme
<pre>
115
import my.interfaces.*
116
117
namespace simple.stuffs {
118
119
	component MySimpleComponent {
120
		provides p1: AnotherJavaInterface
121
	}
122
123
	component MyBeautifulComponent {
124
		provides portName: AJavaInterface
125
		requires anotherPortName: AnotherJavaInterface
126
	}
127
128 5 Anonyme
	component MyComplexComponent {
129
		
130
		provides p1: AnotherJavaInterface
131
		provides p2: AnotherJavaInterface = s.p1
132
		requires p3: AnotherJavaInterface
133 1 Anonyme
134 5 Anonyme
		part b1: MyBeautifulComponent {
135
			bind anotherPortName to s.p1 
136
		}
137 1 Anonyme
138 5 Anonyme
		part b2: MyBeautifulComponent {
139
			bind anotherPortName to p1
140
		}
141
142
		part b3: MyBeautifulComponent {
143
			bind anotherPortName to p3
144
		}
145
		
146
		part s: MySimpleComponent
147
		
148
	}
149
}
150
</pre>
151
152
Interface definition in Java:
153 1 Anonyme
<pre>
154
package my.interfaces;
155
156
public interface AJavaInterface {
157
  public String aMethod(Integer param1);
158
}
159
</pre>
160
161
<pre>
162
package my.interfaces;
163
164
public interface AnotherJavaInterface {
165
	public Integer test();
166
}
167
</pre>
168
169 33 Anonyme
h2. Component Implementation
170 6 Anonyme
171 1 Anonyme
To implement a component, one has to extend the abstract class generated automatically by the Eclipse plugin.
172 33 Anonyme
For example, for the previous example _simple.stuffs.MyBeautifulComponent_ defined in SpeADL, a Java class _simple.stuffs.MyBeautifulComponent_ is generated (in the *speadl-gen* folder, different than the *src* folder).
173 31 Anonyme
174 33 Anonyme
It is not needed to look at the generated code to use it: when extending the class, some abstract methods will have to be implemented.
175 1 Anonyme
176
When implementing a component, one only has to take care of implementing the provided port, and can exploit the required ports without assuming anything about their implementation and who provides it.
177 12 Anonyme
This is one thing that makes a component fundamentally different from an object.
178 31 Anonyme
179 12 Anonyme
h3. Special Methods to Implement
180 7 Anonyme
181 33 Anonyme
Each provided port *p* of interface *I* must be implemented by overriding a method called *I make_p()* which returns an instance of the implementation for the port.
182
This instance is used for the whole life of the component, i.e., the *make_p()* method is called only once to construct the port when the component is instantiated.
183 6 Anonyme
184
Each part *p* of component class *C* has a corresponding abstract method *C make_p()* to override and which must return an instance of an implementation of *C*.
185 7 Anonyme
The bindings and other connections inside the components are totally taken care of by the generated code and the implementation only needs what is Java-specific.
186 6 Anonyme
187 8 Anonyme
Furthermore, optionally, a method *void start()* can be override as explained [[SpeADL_Minus_Reference#Component-Initialisation|below]].
188
189 7 Anonyme
h3. Special Methods to Exploit
190 6 Anonyme
191 31 Anonyme
The *requires()* method (inherited from the extended generated class) gives access to each of the required ports (e.g., _requires().port()_).
192
A port being an implementation of an interface (and not of an operation), it is then necessary to call the desired method on it (e.g., _requires().port().method()_).
193 6 Anonyme
194 32 Anonyme
The *provided()* method  (inherited from the extended generated class) gives access to each of the provided ports in the same manner.
195
196 31 Anonyme
It is possible to access to the provided ports of the part from within the implementation of a composite by using the method *parts()* (e.g., _parts().partName().portName().method()_).
197 6 Anonyme
198
h3. Examples
199
200
Implementing a component with a provided port:
201 1 Anonyme
<pre>
202
package testpackage;
203
204
import my.interfaces.AnotherJavaInterface;
205
import simple.stuffs.MySimpleComponent;
206
207
public class MySimpleComponentImpl extends MySimpleComponent {
208
209
	@Override
210
	protected AnotherJavaInterface make_p1() {
211
		return new AnotherJavaInterface() {
212
			@Override
213
			public Integer test() {
214
				return 10;
215
			}
216
		};
217
	}
218
219
}
220
</pre>
221
222 6 Anonyme
The same result can be obtained by implementing the port directly by the component implementation as follow:
223 1 Anonyme
<pre>
224 6 Anonyme
public class MySimpleComponentImpl extends MySimpleComponent implements AnotherJavaInterface {
225
226
	@Override
227
	public Integer test() {
228
		return 10;
229
	}
230
	
231
	@Override
232
	protected AnotherJavaInterface make_p1() {
233
		return this;
234
	}
235
}
236
</pre>
237
238
Exploiting a required port:
239
<pre>
240 1 Anonyme
package testpackage;
241
242
import my.interfaces.AJavaInterface;
243
import simple.stuffs.MyBeautifulComponent;
244
245
public class MyComponentImpl extends MyBeautifulComponent {
246
247
	@Override
248
	protected AJavaInterface make_portName() {
249
		return new AJavaInterface() {
250
			@Override
251
			public String aMethod(Integer param1) {
252
				return "" + param1 + " and " + requires().anotherPortName().test();
253
			}
254
		};
255
	}
256
}
257
</pre>
258
259 6 Anonyme
Implementing a component with parts, calling a part's provided port:
260 1 Anonyme
<pre>
261
public class ComplexCompImpl extends MyComplexComponent {
262
263
	@Override
264
	protected MySimpleComponent make_s() {
265
		return new MySimpleComponentImpl();
266
	}
267
268
	@Override
269
	protected AnotherJavaInterface make_p1() {
270
		return new AnotherJavaInterface() {
271
			@Override
272
			public Integer test() {
273
				return parts().s().p1().test();
274
			}
275
		};
276
	}
277
278
	@Override
279
	protected MyBeautifulComponent make_b1() {
280
		return new MyComponentImpl();
281
	}
282
283
	@Override
284
	protected MyBeautifulComponent make_b2() {
285
		return new MyComponentImpl();
286
	}
287
288
	@Override
289
	protected MyBeautifulComponent make_b3() {
290
		return new MyComponentImpl();
291
	}
292
293
}
294
</pre>
295
296 39 Anonyme
h2. Component Specialisation
297 16 Anonyme
298
In SpeADL, a basic mechanism exists for specialisation of components.
299
300
h3. Keyword
301
302
When declaring a component class definition, after the name, the keyword *specializes*, followed by a reference to another component name, can be used.
303 1 Anonyme
304 16 Anonyme
h3. Details
305
306 33 Anonyme
307
An implementation of a specialising component can be used in place of the implementation of the specialised component.
308
Only the specialising component needs to be implemented: its implementation will contain all the provided ports of the specialisation hierarchy as well as the parts of the specialising component.
309
310
The specialisation rules are as follow:
311 1 Anonyme
* A component can specialise only a component without parts (i.e., only a pure definition with provided and required ports).
312 31 Anonyme
* A component can override provided ports (while respecting the interface or specialising it) to define delegation.
313 28 Anonyme
* A component can add provided ports.
314 33 Anonyme
* A component CAN'T add required ports (for obvious reason: the specialising component wouldn't be usable in a configuration where the specialised component is used because some of its ports won't be bound).
315 30 Anonyme
316 16 Anonyme
h3. Examples
317
318
<pre>
319
namespace simple.stuffs {
320 26 Anonyme
	component S specializes MySimpleComponent {
321
		provides p2: AnotherJavaInterface
322 16 Anonyme
	}
323
}
324
</pre>
325
326 15 Anonyme
h2. Type Parameters
327
328 33 Anonyme
As in Java, it is possible to exploit type parameters (also called generics) when declaring and referencing components, as well as in the interfaces of the ports.
329 1 Anonyme
330
h3. Keywords
331
332 34 Anonyme
Type parameters are enclosed between *[ * and * ]* (contrary to Java where * <* and *> * are used).
333 1 Anonyme
334
A type parameter can be declared only in a component definition, just after the name declaration.
335 33 Anonyme
It has a unique name, a capital first letter, and can be constrained using the keyword *extends* and the name of a Java class it must be a subclass of.
336 1 Anonyme
337 33 Anonyme
A type parameter can be used as an argument when referencing a component by its name, in a part or in a specialisation declaration.
338 1 Anonyme
It must respect the type parameters declared in the referenced component.
339
340 33 Anonyme
A type parameter can also be used as an argument when referencing an interface by its name in a port declaration.
341 1 Anonyme
Again it must respect the type parameters declared in the interface.
342
343
h3. Details
344
345
The possibilities of expressiveness are equivalent to what can be done in Java.
346
347
The implementation can either keep the type parameters abstract as in the definition, or can concretise them as long as it respects the type parameter declaration.
348
349
Of course interface and component definition references can be parametrised with existing concrete classes.
350
351
h3. Example
352
353
<pre>
354
namespace simple.stuffs {
355
	component ParameterisedComponent1[T extends Number] {
356
		
357
		provides p1: java.util.concurrent.Callable[T]
358
		provides p2: java.util.concurrent.Callable[String]
359
	}
360
	
361
	component ParameterisedComponent2[T1,T2 extends Number] {
362
		
363
		part p1: ParameterisedComponent1[T2] {
364
			
365
		}
366
		
367
		part p2: ParameterisedComponent1[Integer] {
368
			
369
		}
370
		
371
	}
372
}
373
</pre>
374 27 Anonyme
375 39 Anonyme
h2. Component Instantiation
376 33 Anonyme
377
In order to instantiate a component from Java, one need an instance of an implementation of the component and to call the *newComponent()* method (present in the generated class) to get an instance of the component.
378
379
h3. Details
380
381
Only component without required port can be manually instantiated from Java: if a component has required ports, it must be composed with other components in a composite component.
382
383
Once we have an instance of a component, we can call the methods of its provided ports.
384
385
The same applies for composite components, the instantiation of the part of a composite is done automatically by the generated code.
386
387
h3. Example
388
389
<pre>
390
MySimpleComponent.Component c = new MySimpleComponentImpl().newComponent();
391
System.out.println(c.p1().test());
392
</pre>
393
394 27 Anonyme
h2. Component Initialisation
395
396
When the implementation of a component is instantiated (before calling *newComponent()*), its constructor is of course called but the component itself is not yet initialised: in particular its provided required ports and parts can't be called at that time.
397
398
h3. Details
399
400
In order to do some initialisation at the instantiation of a component (during the call to *newComponent()*), one can override the *void start()* method of the extended abstract class.
401
402
h3. Example
403
404
<pre>
405
public class MySimpleComponentImpl extends MySimpleComponent {
406
407
	@Override
408
	protected AnotherJavaInterface make_p1() {
409
		return new AnotherJavaInterface() {
410
			@Override
411
			public Integer test() {
412
				return 10;
413
			}
414
		};
415
	}
416
	
417
	@Override
418
	protected void start() {
419
		// do some initialisation using the requires() or the parts(), create a GUI, etc...
420
	}
421
}
422
</pre>
423
424
h2. Lifecycle of Component Initialisation at Instantiation
425 1 Anonyme
426 40 Anonyme
When *newComponent()* is called on a component implementation, this is what happens:
427 42 Anonyme
# The component is instantiated  (see below).
428
# The instance is started (see below).
429 38 Anonyme
430 22 Anonyme
h3. Component Instantiation
431
432 1 Anonyme
# For each part *partX* in the order of declaration
433 37 Anonyme
## The implementation is instantiated with the *make_partX()* method.
434 38 Anonyme
## A component is instantiated from the implementation following the current procedure.
435 23 Anonyme
# For each provided port *portX* in the order of declaration (starting with the super-component in case of specialisation)
436 36 Anonyme
## The interface implementation is instantiated with the *make_portX()* method.
437
438 40 Anonyme
h3. Component Instance Start
439 22 Anonyme
440
# For each part *partX* in the order of declaration
441 41 Anonyme
## The part is started following the current procedure.
442 22 Anonyme
# The implementation *start()* method is called.