Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 45

Anonyme, 15/10/2014 16:10

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