Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 1

Anonyme, 03/10/2014 16:54

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