SpeADL Minus Reference » Historique » Version 16
Anonyme, 06/10/2014 11:21
| 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 | Contrary to Java, type parameters are enclosed between *[* and *]*. |
||
| 370 | |||
| 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> |