Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 5

Anonyme, 06/10/2014 10:12

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 5 Anonyme
The keywords *provided* and *required* 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 *provided name: Interface* or *required 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
It takes the form "provided name: Interface = name.port* or "provided name: Interface = port*.
91
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 that provides a port will thus provide an implementation for its interface in the component class implementation.
97 1 Anonyme
Inversely, a component that requires a port can use in its implementation the methods of the interface of the required port.
98
99 5 Anonyme
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.
100 1 Anonyme
101
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.
102
This is what makes a component fundamentally different from an object.
103
104 5 Anonyme
In SpeADL, one can use completion to complete interface names.
105
Also, the shortcut to organize imports will take interfaces into account.
106
107
h3. Example
108
109
Component class definitions
110 1 Anonyme
<pre>
111
import my.interfaces.*
112
113
namespace simple.stuffs {
114
115
	component MySimpleComponent {
116
		provides p1: AnotherJavaInterface
117
	}
118
119
	component MyBeautifulComponent {
120
		provides portName: AJavaInterface
121
		requires anotherPortName: AnotherJavaInterface
122
	}
123
124 5 Anonyme
	component MyComplexComponent {
125
		
126
		provides p1: AnotherJavaInterface
127
		provides p2: AnotherJavaInterface = s.p1
128
		requires p3: AnotherJavaInterface
129 1 Anonyme
130 5 Anonyme
		part b1: MyBeautifulComponent {
131
			bind anotherPortName to s.p1 
132
		}
133 1 Anonyme
134 5 Anonyme
		part b2: MyBeautifulComponent {
135
			bind anotherPortName to p1
136
		}
137
138
		part b3: MyBeautifulComponent {
139
			bind anotherPortName to p3
140
		}
141
		
142
		part s: MySimpleComponent
143
		
144
	}
145
}
146
</pre>
147
148
Interface definition in Java:
149 1 Anonyme
<pre>
150
package my.interfaces;
151
152
public interface AJavaInterface {
153
  public String aMethod(Integer param1);
154
}
155
</pre>
156
157
<pre>
158
package my.interfaces;
159
160
public interface AnotherJavaInterface {
161
	public Integer test();
162
}
163
</pre>
164
165
h2. Implementations
166
167
To implement a component, one has to extend the abstract class generated automatically by the Eclipse plugin.
168
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).
169
170
It is not needed to look at the generated code to use it: when extending the class, some abstract methods must be implemented.
171
It is a good idea to use the errors shown by the Eclipse Java editor and their quick-fixes to quickly generate the skeleton of the implementation itself.
172
173
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 during 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).
174
Usually, one returns in this method an anonymous instance of the interface as the following Java files show:
175
176
<pre>
177
package testpackage;
178
179
import my.interfaces.AnotherJavaInterface;
180
import simple.stuffs.MySimpleComponent;
181
182
public class MySimpleComponentImpl extends MySimpleComponent {
183
184
	@Override
185
	protected AnotherJavaInterface make_p1() {
186
		return new AnotherJavaInterface() {
187
			@Override
188
			public Integer test() {
189
				return 10;
190
			}
191
		};
192
	}
193
194
}
195
</pre>
196
197
<pre>
198
package testpackage;
199
200
import my.interfaces.AJavaInterface;
201
import simple.stuffs.MyBeautifulComponent;
202
203
public class MyComponentImpl extends MyBeautifulComponent {
204
205
	@Override
206
	protected AJavaInterface make_portName() {
207
		return new AJavaInterface() {
208
			@Override
209
			public String aMethod(Integer param1) {
210
				return "" + param1 + " and " + requires().anotherPortName().test();
211
			}
212
		};
213
	}
214
}
215
</pre>
216
217
But the same result can be obtained by implementing the port directly by the component implementation as follow:
218
<pre>
219
public class MyComponentImpl extends MyBeautifulComponent implements AJavaInterface {
220
221
	@Override
222
	public String aMethod(Integer param1) {
223
		return "" + param1 + " and " + requires().anotherPortName().test();
224
	}
225
	
226
	@Override
227
	protected AJavaInterface make_portName() {
228
		return this;
229
	}
230
}
231
</pre>
232
233
We can see that the class extends simple.stuffs.MyBeautifulComponent and that it overrides a method named *make_portName()* after the name of the provided port.
234
235
Finally, the *requires()* method (inherited from the extended generated class, *MyBeautifulComponent* in the example) gives access to each of the required ports (e.g.,*requires().anotherPortName()* in the example).
236
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().anotherPortName().test()* in the example).
237
238
Of course, nothing else is required than calling it to use it: as we are going to see now, the implementation of a required port is provided by another component composed with the requiring component.
239
240
h2. Composites
241
242
While defining a component class with a name and ports in SpeADL is only a definition of its external interfaces, a composite of many components connected together is already a partial implementation of this definition.
243
244
A composite, on top of provided and required ports, contains parts. A part is structurally similar to a class member in Java.
245
A part is declared using the *part* keyword and the name of the component class of the part.
246
Furthermore, if the component class of the part has required ports, then a part will also contain bindings for these required ports using the keyword *bind*.
247
248
An example follow:
249
<pre>
250
namespace simple.stuffs {
251
	component MyComplexComponent {
252
		
253
		provides p1: AnotherJavaInterface
254
		provides p2: AnotherJavaInterface = s.p1
255
		requires p3: AnotherJavaInterface
256
257
		part b1: MyBeautifulComponent {
258
			bind anotherPortName to s.p1 
259
		}
260
261
		part b2: MyBeautifulComponent {
262
			bind anotherPortName to p1
263
		}
264
265
		part b3: MyBeautifulComponent {
266
			bind anotherPortName to p3
267
		}
268
		
269
		part s: MySimpleComponent
270
		
271
	}
272
}
273
</pre>
274
275
The keyword *bind* is followed by the name of the required port that is to be bound (completion can be used), then by the keyword *to* then either by:
276
* The name of another part, a dot, then a provided port of this part (as for *b1* in the example).
277
* The name of a provided port of the component containing the part (as for *b2* in the example).
278
* The name of a required port of the component containing the part (as for *b3* in the example).
279 3 Anonyme
280 1 Anonyme
Furthermore, another type of binding is a delegation of a provided port to another port.
281
It is declared using the = sign after the provided port declaration (as in *p2* in the example) and can be followed either by a reference to the port of a part, a provided or a required port of the component, as with the normal bindings.
282
283
h2. Implementation of Composites
284
285
As with the implementation of non-composite component classes, a Java class is generated from the description and it must be extended in order to specify the implementation of the provided ports and of the parts.
286
287
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*.
288
289
For example:
290
<pre>
291
public class ComplexCompImpl extends MyComplexComponent {
292
293
	@Override
294
	protected MySimpleComponent make_s() {
295
		return new MySimpleComponentImpl();
296
	}
297
298
	@Override
299
	protected AnotherJavaInterface make_p1() {
300
		return new AnotherJavaInterface() {
301
			@Override
302
			public Integer test() {
303
				return parts().s().p1().test();
304
			}
305
		};
306
	}
307
308
	@Override
309
	protected MyBeautifulComponent make_b1() {
310
		return new MyComponentImpl();
311
	}
312
313
	@Override
314
	protected MyBeautifulComponent make_b2() {
315
		return new MyComponentImpl();
316
	}
317
318
	@Override
319
	protected MyBeautifulComponent make_b3() {
320
		return new MyComponentImpl();
321
	}
322
323
}
324
</pre>
325
326
As we can see, 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.
327
It becomes very easy to define new compositions without extra boilerplate code.
328
329
Also, it is possible to access to the provided ports of the part from within the implementation of a composite by using the method *parts()* (as in the implementation of the port *p1* in the example).
330
331
h2. Instantiation
332
333
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.
334
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.
335
336
For example:
337
<pre>
338
MySimpleComponent.Component c = new MySimpleComponentImpl().newComponent();
339
System.out.println(c.p1().test());
340
</pre>
341
342
As we can see, once we have an instance of a component, we can call the methods of its provided ports.
343
344
The same applies for composite components, the instantiation of the part of a composite is done automatically by the generated code.
345
346
h2. Component Initialisation
347
348
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.
349
350
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:
351
352
<pre>
353
public class MySimpleComponentImpl extends MySimpleComponent {
354
355
	@Override
356
	protected AnotherJavaInterface make_p1() {
357
		return new AnotherJavaInterface() {
358
			@Override
359
			public Integer test() {
360
				return 10;
361
			}
362
		};
363
	}
364
	
365
	@Override
366
	protected void start() {
367
		// do some initialisation using the requires() or the parts(), create a GUI, etc...
368
	}
369
}
370
</pre>