Reference Guides » Historique » Révision 7
« Précédent |
Révision 7/22
(diff)
| Suivant »
Anonyme, 03/10/2014 13:30
SpeADL Reference¶
SpeADL is a language to describe component-oriented architectures and implement them in Java.
This page is decomposed in two parts:- SpeADL⁻ : it concerns the traditional component-oriented abstractions such as components, interfaces, composites, specialisation, provided and required ports, bindings, etc
- SpeADL: it concerns the specific abstractions introduced by SpeADL to help the development of MAS with ecosystems and species.
SpeADL⁻¶
In SpeADL, a set of abstractions are provided to define traditional component-oriented architectures.
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.
A component is made of two elements: a component class definition using SpeADL and an implementation using Java.
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.
Namespaces¶
Components and composites are defined inside namespace using the keyword namespace.
A namespace plays the exact same role as a package in Java.
In a SpeADL file, there can be many as namespace (as well as nested ones) as wanted.
Hence a namespace does not have to follow the name of the directory it is located in as in Java.
Here is an example of namespace declarations:
namespace simple {
namespace things {
}
}
namespace simple.stuffs {
}
Each namespace declaration can contain any component as desired as we are going to see.
Imports¶
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.
The syntax is similar to Java:
import java.util.Collection import java.util.* import simple.stuffs.*
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.
The imports can be automatically handled and reorganised in Eclipse using the Ctrl-Shift-O shortcut as in the Java editor.
Components and Ports¶
A component is made of a component class definition and an implementation: it can then be instantiated
The definition gives it a name and a list of ports that are either provided or required by the component.
Each port has a name and an interface.
An interface is understood as a Java interface, i.e., a collection of methods.
A component that provides a port must thus provide an implementation for its interface.
Inversely, a component that requires a port can use in its implementation the methods of the interface of the required port.
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.
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.
This is what makes a component fundamentally different from an object.
A component is defined using the following syntax:
import my.interfaces.*
namespace simple.stuffs {
component MyBeautifulComponent {
provides portName: AJavaInterface
requires anotherPortName: AnotherJavaInterface
}
}
A component is defined using the keyword component, has a name and can contains as many port declaration as wanted.
A port has a name and an interface.
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.
Obviously, having an interface means that there must exist already an interface defined with the same name.
Such a definition is done in Java as one would normally do, for example, as follow, in Java files:
package my.interfaces;
public interface AJavaInterface {
public String aMethod(Integer param1);
}
package my.interfaces;
public interface AnotherJavaInterface {
public Integer test();
}
In SpeADL, one can use completion to complete interface names.
Also, the shortcut to organize imports will take interfaces into account.
Implementations¶
To implement a component, one has to extend the abstract class generated automatically by the Eclipse plugin.
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).
It is not needed to look at the generated code to use it: when extending the class, some abstract methods must be implemented.
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.
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).
Usually, one returns in this method an anonymous instance of the interface as the following Java file shows:
package testpackage;
import my.interfaces.AJavaInterface;
import simple.stuffs.MyBeautifulComponent;
public class ComponentImpl extends MyBeautifulComponent {
@Override
protected AJavaInterface make_portName() {
return new AJavaInterface() {
@Override
public String aMethod(Integer param1) {
return "" + param1 + " and " + requires().anotherPortName().test();
}
};
}
}
But the same result can be obtained by implementing the port directly by the component implementation as follow:
public class ComponentImpl extends MyBeautifulComponent implements AJavaInterface {
@Override
public String aMethod(Integer param1) {
return "" + param1 + " and " + requires().anotherPortName().test();
}
@Override
protected AJavaInterface make_portName() {
return this;
}
}
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.
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).
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).
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.
Composites¶
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.
A composite, on top of provided and required ports, contains parts. A part is structurally similar to a class member in Java.
A part is declared using the part keyword and the name of the component class of the part.
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.
An example follow:
namespace simple.stuffs {
component MySimpleComponent {
provides p1: AnotherJavaInterface
}
component MyComplexComponent {
provides p1: AnotherJavaInterface
provides p2: AnotherJavaInterface = s.p1
requires p3: AnotherJavaInterface
part b1: MyBeautifulComponent {
bind anotherPortName to s.p1
}
part b2: MyBeautifulComponent {
bind anotherPortName to p1
}
part b3: MyBeautifulComponent {
bind anotherPortName to p3
}
part s: MySimpleComponent
}
}
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:
- The name of another part, a dot, then a provided port of this part (as for b1 in the example).
- The name of a provided port of the component containing the part (as for b2 in the example).
- The name of a required port of the component containing the part (as for b3 in the example).
Furthermore, another type of binding is a delegation of a provided port to another port.
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.
Mis à jour par Anonyme il y a plus de 11 ans · 22 révisions