Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 30

Anonyme, 07/10/2014 15:39

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