Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 32

Anonyme, 09/10/2014 15:58

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