Projet

Général

Profil

SpeADL Minus Reference » Historique » Version 4

Anonyme, 06/10/2014 09:48

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