Projet

Général

Profil

Reference Guides » Historique » Version 12

Anonyme, 03/10/2014 14:53

1 1 Anonyme
h1. SpeADL Reference
2
3 12 Anonyme
{{>toc}}
4
5 1 Anonyme
SpeADL is a language to describe component-oriented architectures and implement them in Java.
6
7
This page is decomposed in two parts:
8 2 Anonyme
# SpeADL⁻ : it concerns the traditional component-oriented abstractions such as components, interfaces, composites, specialisation, provided and required ports, bindings, etc
9 1 Anonyme
# SpeADL: it concerns the specific abstractions introduced by SpeADL to help the development of MAS with ecosystems and species.
10
11 2 Anonyme
h2. SpeADL⁻
12 1 Anonyme
13
In SpeADL, a set of abstractions are provided to define traditional component-oriented architectures.
14
With it, it is possible to define components and compositions of components, called composites, and to implement them in Java while keeping a strong link between definition and implementation by relying on an Eclipse plugin.
15
16 6 Anonyme
A component is made of two elements: a component class definition using SpeADL and an implementation using Java.
17 1 Anonyme
From the SpeADL definition, an abstract Java class is automatically generated and then relied upon through the Java extension mechanism to implement it in a safe manner.
18
19
h3. Namespaces
20
21
Components and composites are defined inside namespace using the keyword *namespace*.
22
A namespace plays the exact same role as a package in Java.
23
24
In a SpeADL file, there can be many as namespace (as well as nested ones) as wanted.
25
Hence a namespace does not have to follow the name of the directory it is located in as in Java.
26
27
Here is an example of namespace declarations:
28
<pre>
29
namespace simple {
30
31 6 Anonyme
	namespace things {
32
	}
33 1 Anonyme
}
34
35
namespace simple.stuffs {
36
}
37
</pre>
38
39
Each namespace declaration can contain any component as desired as we are going to see.
40
41
h3. Imports
42
43
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) using the keyword *import*.
44
45
The syntax is similar to Java:
46
<pre>
47
import java.util.Collection
48
import java.util.*
49
import simple.stuffs.*
50
</pre>
51
52 6 Anonyme
Notice that namespace of components are also considered to import component class definitions, and that there is no semi-colon ";" at the end of the line.
53 1 Anonyme
54
The imports can be automatically handled and reorganised in Eclipse using the *Ctrl-Shift-O* shortcut as in the Java editor.
55
56
h3. Components and Ports
57
58 6 Anonyme
A component is made of a component class definition and an implementation: it can then be instantiated 
59 1 Anonyme
The definition gives it a name and a list of ports that are either provided or required by the component.
60
Each port has a name and an interface.
61
An interface is understood as a Java interface, i.e., a collection of methods.
62
63
A component that provides a port must thus provide an implementation for its interface.
64
Inversely, a component that requires a port can use in its implementation the methods of the interface of the required port.
65
66
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: this is covered in the next section.
67
68
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.
69
This is what makes a component fundamentally different from an object.
70
71
A component is defined using the following syntax:
72
<pre>
73
import my.interfaces.*
74
75
namespace simple.stuffs {
76 12 Anonyme
77
	component MySimpleComponent {
78
		provides p1: AnotherJavaInterface
79
	}
80
81 6 Anonyme
	component MyBeautifulComponent {
82
		provides portName: AJavaInterface
83
		requires anotherPortName: AnotherJavaInterface
84
	}
85 1 Anonyme
}
86
</pre>
87
88
A component is defined using the keyword *component*, has a name and can contains as many port declaration as wanted.
89
90
A port has a name and an interface.
91
The keywords *provides* and *requires* respectfully represents ports that are provided and required by the component and are a mandatory keyword when defining a port inside a component.
92
93
Obviously, having an interface means that there must exist already an interface defined with the same name.
94 3 Anonyme
Such a definition is done in Java as one would normally do, for example, as follow, in Java files:
95 1 Anonyme
<pre>
96
package my.interfaces;
97
98 3 Anonyme
public interface AJavaInterface {
99 1 Anonyme
  public String aMethod(Integer param1);
100
}
101
</pre>
102
103 3 Anonyme
<pre>
104
package my.interfaces;
105
106
public interface AnotherJavaInterface {
107
	public Integer test();
108
}
109
</pre>
110
111 1 Anonyme
In SpeADL, one can use completion to complete interface names.
112
Also, the shortcut to organize imports will take interfaces into account.
113 3 Anonyme
114
h3. Implementations
115
116 6 Anonyme
To implement a component, one has to extend the abstract class generated automatically by the Eclipse plugin.
117 3 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).
118
119
It is not needed to look at the generated code to use it: when extending the class, some abstract methods must be implemented.
120 1 Anonyme
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.
121
122 3 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 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).
123 12 Anonyme
Usually, one returns in this method an anonymous instance of the interface as the following Java files show:
124
125 1 Anonyme
<pre>
126
package testpackage;
127
128 12 Anonyme
import my.interfaces.AnotherJavaInterface;
129
import simple.stuffs.MySimpleComponent;
130
131
public class MySimpleComponentImpl extends MySimpleComponent {
132
133
	@Override
134
	protected AnotherJavaInterface make_p1() {
135
		return new AnotherJavaInterface() {
136
			@Override
137
			public Integer test() {
138
				return 10;
139
			}
140
		};
141
	}
142
143
}
144
</pre>
145
146
<pre>
147
package testpackage;
148
149 3 Anonyme
import my.interfaces.AJavaInterface;
150 6 Anonyme
import simple.stuffs.MyBeautifulComponent;
151 3 Anonyme
152 9 Anonyme
public class MyComponentImpl extends MyBeautifulComponent {
153 3 Anonyme
154
	@Override
155
	protected AJavaInterface make_portName() {
156
		return new AJavaInterface() {
157
			@Override
158
			public String aMethod(Integer param1) {
159
				return "" + param1 + " and " + requires().anotherPortName().test();
160
			}
161 1 Anonyme
		};
162 4 Anonyme
	}
163
}
164
</pre>
165
166
But the same result can be obtained by implementing the port directly by the component implementation as follow:
167
<pre>
168 9 Anonyme
public class MyComponentImpl extends MyBeautifulComponent implements AJavaInterface {
169 4 Anonyme
170 1 Anonyme
	@Override
171
	public String aMethod(Integer param1) {
172
		return "" + param1 + " and " + requires().anotherPortName().test();
173
	}
174
	
175
	@Override
176
	protected AJavaInterface make_portName() {
177
		return this;
178 6 Anonyme
	}
179 1 Anonyme
}
180 6 Anonyme
</pre>
181
182 1 Anonyme
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.
183 6 Anonyme
184
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).
185 1 Anonyme
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).
186 6 Anonyme
187
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.
188
189
h3. Composites
190
191
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.
192
193
A composite, on top of provided and required ports, contains parts. A part is structurally similar to a class member in Java.
194
A part is declared using the *part* keyword and the name of the component class of the part.
195
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*.
196
197
An example follow:
198
<pre>
199
namespace simple.stuffs {
200
	component MyComplexComponent {
201
		
202 7 Anonyme
		provides p1: AnotherJavaInterface
203
		provides p2: AnotherJavaInterface = s.p1
204
		requires p3: AnotherJavaInterface
205
206
		part b1: MyBeautifulComponent {
207 6 Anonyme
			bind anotherPortName to s.p1 
208 1 Anonyme
		}
209 7 Anonyme
210
		part b2: MyBeautifulComponent {
211
			bind anotherPortName to p1
212
		}
213
214
		part b3: MyBeautifulComponent {
215
			bind anotherPortName to p3
216
		}
217 6 Anonyme
		
218
		part s: MySimpleComponent
219
		
220
	}
221
}
222 7 Anonyme
</pre>
223
224
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:
225
* The name of another part, a dot, then a provided port of this part (as for *b1* in the example).
226
* The name of a provided port of the component containing the part (as for *b2* in the example).
227
* The name of a required port of the component containing the part (as for *b3* in the example).
228 1 Anonyme
229
Furthermore, another type of binding is a delegation of a provided port to another port.
230 9 Anonyme
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.
231
232
h3. Implementation of Composites
233
234
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.
235
236
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*.
237
238
For example:
239
<pre>
240
public class ComplexCompImpl extends MyComplexComponent {
241
242
	@Override
243
	protected MySimpleComponent make_s() {
244 1 Anonyme
		return new MySimpleComponentImpl();
245 9 Anonyme
	}
246
247
	@Override
248
	protected AnotherJavaInterface make_p1() {
249
		return new AnotherJavaInterface() {
250
			@Override
251
			public Integer test() {
252 12 Anonyme
				return parts().s().p1().test();
253 9 Anonyme
			}
254
		};
255
	}
256
257
	@Override
258
	protected MyBeautifulComponent make_b1() {
259
		return new MyComponentImpl();
260
	}
261
262
	@Override
263
	protected MyBeautifulComponent make_b2() {
264
		return new MyComponentImpl();
265
	}
266
267
	@Override
268
	protected MyBeautifulComponent make_b3() {
269 1 Anonyme
		return new MyComponentImpl();
270
	}
271
272
}
273
</pre>
274
275
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.
276
It becomes very easy to define new compositions without extra boilerplate code.
277 12 Anonyme
278
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).
279
280
h3. 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
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.
284
285
For example:
286
<pre>
287
MySimpleComponent.Component c = new MySimpleComponentImpl().newComponent();
288
System.out.println(c.p1().test());
289
</pre>
290
291
As we can see, once we have an instance of a component, we can call the methods of its provided ports.
292
293
The same applies for composite components, the instantiation of the part of a composite is done automatically by the generated code.
294
295
h3. Component Initialisation
296
297
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.
298
299
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:
300
301
<pre>
302
public class MySimpleComponentImpl extends MySimpleComponent {
303
304
	@Override
305
	protected AnotherJavaInterface make_p1() {
306
		return new AnotherJavaInterface() {
307
			@Override
308
			public Integer test() {
309
				return 10;
310
			}
311
		};
312
	}
313
	
314
	@Override
315
	protected void start() {
316
		// do some initialisation using the requires() or the parts(), create a GUI, etc...
317
	}
318
}
319
</pre>