SpeADL Minus Tutorial » Historique » Révision 6
Révision 5 (Anonyme, 06/10/2014 15:53) → Révision 6/20 (Anonyme, 06/10/2014 16:13)
h1. SpeADL Minus Tutorial
{{>toc}}
This is a tutorial for [[SpeADL Minus Reference|SpeADL⁻]]: creating a project, defining simple and composite components, implementing components.
h2. Objectives
The objective of this tutorial is to understand the basic workflow to follow when developing component-oriented applications with SpeADL in Eclipse/MAY.
We will create a simple composition of two components connected together following a typical client-server configuration.
The server will provide a service that will be used by the client.
They will be composed together in a big component.
A Java *main()* will be created to show how to execute the composition from Java. once.
A very simple GUI will be used to illustrate a self-contained component acting as an application.
h2. Installing Eclipse and MAY
This procedure is described on [[SpeADL MAY Project SetUp|this page]].
h2. Creating a New Project
First, we must create a project to work.
In Eclipse, go to the menus : *File / New / Java Project*.
Enter _Tutorial 1_ as the project name, verify that the *execution environment JRE* is 1.5 or above.
As a start, create a package in the *src* folder called _tutorial1_.
h2. The Server Component
h3. Organisation
Create the following hierarchy of packages (See [[SpeADL Best Practices#Project Organisation|this best practice]] for details on the matter):
* _tutorial1.server_
** _impl_
** _interfaces_
h3. Defining the Component
Create a SpeADL file:
* Right-click on tutorial1.server and select *New / File*.
* Enter _server.speadl_ as the file name.
Define the namespace we are going to work in as well as the _Server_ component:
<pre>
namespace tutorial1.server {
component ServerComponentType {
}
}
</pre>
Save and confirm that the *speadl-gen* folder was automatically added to the project source folders and that it contains a Java class generated in the package _tutorial1.server_ named _ServerComponentType_.
h3. Defining a Port and its Interface
The _Server_ component will provide a port whose interface contains one method to give the contrary of a boolean.
Add it to the component declaration:
<pre>
namespace tutorial1.server {
component ServerComponentType {
provides service: NotSoNiceServiceType
}
}
</pre>
Because the _NotSoNiceServiceType_ interface does not yet exist, there is an error in the SpeADL editor.
We will store the interface in the _tutorial1.server.interfaces_ package.
Either create it by hand or use the Quick Fix proposed by SpeADL editor by hovering on the error.
<pre>
package tutorial1.server.interfaces;
public interface NotSoNiceServiceType {
public boolean contrary(boolean b);
}
</pre>
Save, and go back to the SpeADL editor for _server.speadl_.
Call the automatic import organiser with *Ctrl+Shift+O*.
Confirm that an import was added on top of the SpeADL file and save.
h3. Implementing the Component
Create a new Java class in _tutorial1.server.impl_ named ServerImpl, and edit it so that it extends ServerComponentType:
<pre>
public class ServerImpl extends ServerComponentType {
}
</pre>
Notice that completion can be exploited as _ServerComponentType_ is an actual Java type, but that calling *F3* on it redirects directly to the SpeADL file.
Because there is abstract method to implement in _ServerComponentType_, there is errors in the Java editor.
Use the Quick Fix *Add unimplemented methods* by hovering on the error on the class name _ServerImpl_:
<pre>
public class ServerImpl extends ServerComponentType {
@Override
protected NotSoNiceServiceType make_service() {
// TODO Auto-generated method stub
return null;
}
}
</pre>
Remove the *TODO* line and replace _null_ with _new NotSoNiceServiceType_, call completion (*Ctrl+Space*) and choose *NotSoNiceServiceType() Anonymous Inner Type*:
<pre>
public class ServerImpl extends ServerComponentType {
@Override
protected NotSoNiceServiceType make_service() {
return new NotSoNiceServiceType() {
@Override
public boolean contrary(boolean b) {
// TODO Auto-generated method stub
return false;
}
};
}
}
</pre>
Remove the *TODO* line and replace _return false;_ by _return !b;_:
<pre>
package tutorial1.server.impl;
import tutorial1.server.ServerComponentType;
import tutorial1.server.interfaces.NotSoNiceServiceType;
public class ServerImpl extends ServerComponentType {
@Override
protected NotSoNiceServiceType make_service() {
return new NotSoNiceServiceType() {
@Override
public boolean contrary(boolean b) {
return !b;
}
};
}
}
</pre>
h2. The Client Component
h3. Organisation
Create the following hierarchy of packages:
* _tutorial1.client_
** _impl_
** _interfaces_
** _datatypes_
h3. Defining the Component
Create a SpeADL file in _tutorial1.client_ named _client.speadl_.
Define the namespace we are going to work in as well as the _Client_ component:
<pre>
namespace tutorial1.client {
component ClientComponentType {
}
}
</pre>
Save and confirm that the *speadl-gen* folder contains a Java class generated in the package _tutorial1.client_ named _ClientComponentType_.
h3. Defining the Ports, their Interfaces and Datatypes
The Client component will provides a port computing a request and will need the _NotSoNiceServiceType_ to do its job:
<pre>
import tutorial1.server.interfaces.NotSoNiceServiceType
namespace tutorial1.client {
component ClientComponentType {
provides service: ASupeNiceService
requires helper: NotSoNiceServiceType
}
}
</pre>
Don't hesitate to exploit completion (*Ctrl+Space*) and automatic import organiser (*Ctrl+Shift+O*) to type the interfaces names.
As before, an error appears in the editor because _ASupeNiceService_ does not exists, create it in _tutorial1.client.interfaces_:
<pre>
package tutorial1.client.interfaces;
public interface ASupeNiceService {
public Request compute(Request r);
}
</pre>
As we can see, we rely on a type named _Request_.
Create it in _tutorial1.client.datatypes_:
<pre>
package tutorial1.client.datatypes;
public class Request {
public final boolean b;
public Request(boolean b) {
this.b = b;
}
}
</pre>
h3. Implementing the Component
Create a new Java class in tutorial1.client.impl named ClientImpl.
Edit it so that it extends _ClientComponentType_ and resolve all the errors to generate its complete skeleton:
<pre>
package tutorial1.client.impl;
import tutorial1.client.ClientComponentType;
import tutorial1.client.datatypes.Request;
import tutorial1.client.interfaces.ASupeNiceService;
public class ClientImpl extends ClientComponentType {
@Override
protected ASupeNiceService make_service() {
return new ASupeNiceService() {
@Override
public Request compute(Request r) {
// TODO Auto-generated method stub
return null;
}
};
}
}
</pre>
Implement the _compute()_ method to call the required port _helper_ to actually do the computation and to return a new _Request_:
<pre>
public class ClientImpl extends ClientComponentType {
@Override
protected ASupeNiceService make_service() {
return new ASupeNiceService() {
@Override
public Request compute(Request r) {
final boolean contrary = requires().helper().contrary(r.b);
return new Request(contrary);
}
};
}
}
</pre>
h2. The Composite Component
In order to use the Client and the Server components together, we need to build a composite component connecting them together.
h3. Defining the Component
Create a SpeADL file in _tutorial1.composite_ _tutorial1_ named _composite.speadl_. _application.speadl_.
Define the namespace we are going to work in as well as the _CompositeComponentType_ _Application_ component:
<pre>
namespace tutorial1.composite tutorial1 {
component CompositeComponentType Application {
}
}
</pre>
Save.
h3. Defining the Composition
In CompositeComponentType, Application, there will be one server Server and one client Client for now.
Declare them as parts in the composite Application component:
<pre>
import tutorial1.client.ClientComponentType
import tutorial1.server.ServerComponentType
namespace tutorial1.composite tutorial1 {
component CompositeComponentType Application {
part server: ServerComponentType {
}
part client: ClientComponentType {
}
}
}
</pre>
An error is present in the editor on the _client_ name to express that some required ports of client are not bound.
Using the *bind ... to ...* keyword by it:
<pre>
namespace tutorial1.composite tutorial1 {
component CompositeComponentType Application {
part server: ServerComponentType {
}
part client: ClientComponentType {
bind helper to server.service
}
}
}
</pre>
Save.
h3. Implementing the Component
Create a new Java class in tutorial1.composite.impl named CompositeImpl.
Edit it so that it extends _CompositeComponentType_ and resolve all the errors to generate its complete skeleton:
<pre>
package tutorial1.composite.impl;
import tutorial1.CompositeComponentType;
import tutorial1.client.ClientComponentType;
import tutorial1.server.ServerComponentType;
public class CompositeImpl extends CompositeComponentType {
@Override
protected ServerComponentType make_server() {
// TODO Auto-generated method stub
return null;
}
@Override
protected ClientComponentType make_client() {
// TODO Auto-generated method stub
return null;
}
}
</pre>
For the _server_ part, return a new instance of the implementation _ServerImpl_ , and the same for the _client_ part with _ClientImpl_:
<pre>
public class CompositeImpl extends CompositeComponentType {
@Override
protected ServerComponentType make_server() {
return new ServerImpl();
}
@Override
protected ClientComponentType make_client() {
return new ClientImpl();
}
}
</pre>
h3. Creating an Application
We can now instantiate this composition in an application.
Create a Java class named _Application_ in _tutorial1_ with a *static void main()* method.
Create an instance of the composite component in it:
<pre>
package tutorial1;
import tutorial1.composite.CompositeComponentType;
import tutorial1.composite.impl.CompositeImpl;
public class Application {
public static void main(String[] args) {
CompositeComponentType.Component component = new CompositeImpl().newComponent();
}
}
</pre>
Unfortunately, we forgot to provide a port on this component: it is thus impossible for us to access to the client component inside.
h3. Adding a Delegating Port
In order to be able to use the composite component from Java, we thus need a provided port, and it will delegate to the provided port of the client component.
Edit the SpeADL file _composite.speadl_ to add such a delegation:
<pre>
import tutorial1.client.ClientComponentType
import tutorial1.client.interfaces.ASupeNiceService
import tutorial1.server.ServerComponentType
namespace tutorial1.composite {
component CompositeComponentType {
provides service: ASupeNiceService = client.service
part server: ServerComponentType {
}
part client: ClientComponentType {
bind helper to server.service
}
}
}
</pre>
This is all that is needed for it to work.
h3. Running the Application
Edit the Application class to call the newly added port:
<pre>
package tutorial1;
import tutorial1.client.datatypes.Request;
import tutorial1.composite.CompositeComponentType;
import tutorial1.composite.impl.CompositeImpl;
public class Application {
public static void main(String[] args) {
CompositeComponentType.Component component = new CompositeImpl().newComponent();
Request input = new Request(true);
Request output = component.service().compute(input);
System.out.println(output.b);
}
}
</pre>
Right-click on the *main()* method and select *Run As / Java Application*.
Confirm that *false* is printed in the console as expected.