Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 17

Anonyme, 06/10/2014 12:35

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