Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 38

Anonyme, 13/10/2014 17:18

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