Projet

Général

Profil

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.