Projet

Général

Profil

SpeADL Minus Tutorial » Historique » Révision 11

Révision 10 (Anonyme, 14/10/2014 13:35) → Révision 11/20 (Anonyme, 14/10/2014 13:35)

h1. SpeADL Minus Tutorial 

 {{>toc}} 

 This is a tutorial for [[SpeADL Minus Reference|SpeADL⁻]]: creating a project, defining simple and composite components, implementing components. 
 An Eclipse project with the code is provided at the end of this page. 

 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. 
 An Java Application will be created to show how to execute the composition from Java. 
 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 [[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 [[MAY [[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_ named _composite.speadl_. 

 Define the namespace we are going to work in as well as the _CompositeComponent_ component: 
 <pre> 
 namespace tutorial1.composite { 
	 component CompositeComponent { 
		
	 } 
 } 
 </pre> 

 Save. 

 h3. Defining the Composition 

 In CompositeComponent, there will be one server and one client for now. 
 Declare them as parts in the composite component: 
 <pre> 
 import tutorial1.client.ClientComponentType 
 import tutorial1.server.ServerComponentType 

 namespace tutorial1.composite { 
	 component CompositeComponent { 
		 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 { 
	 component CompositeComponent { 
		 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 _CompositeComponent_ and resolve all the errors to generate its complete skeleton: 
 <pre> 
 package tutorial1.composite.impl; 

 import tutorial1.CompositeComponent; 
 import tutorial1.client.ClientComponentType; 
 import tutorial1.server.ServerComponentType; 

 public class CompositeImpl extends CompositeComponent { 

	 @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 CompositeComponent { 

	 @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.CompositeComponent; 
 import tutorial1.composite.impl.CompositeImpl; 

 public class Application { 

	 public static void main(String[] args) { 
		 CompositeComponent.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 CompositeComponent { 
		
		 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.CompositeComponent; 
 import tutorial1.composite.impl.CompositeImpl; 

 public class Application { 

	 public static void main(String[] args) { 
		 CompositeComponent.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. 

 h2. A Self-Contained Application 

 It can be desired that a composition of component is considered a self-contained application, for example with a GUI to execute the client. 
 We will use that example to illustrate the use of the *start()* method. 

 h3. A GUI Component 

 First, let's create a GUI component: create a file _gui.speadl_ in the package _tutorial1.gui_ containing the definition of our component: 
 <pre> 
 import tutorial1.client.interfaces.ASupeNiceService 

 namespace tutorial1.gui { 
	 component GUIComponent { 
		 requires service: ASupeNiceService 
	 } 	
 } 
 </pre> 

 h3. Component Implementation 

 Then the implementation _GUIImpl_ in Java in the package _tutorial1.gui.impl_ exploiting the required port: 
 <pre> 
 package tutorial1.gui.impl; 

 import java.awt.BorderLayout; 
 import java.awt.GridLayout; 
 import java.awt.event.ActionEvent; 
 import java.awt.event.ActionListener; 

 import javax.swing.JButton; 
 import javax.swing.JCheckBox; 
 import javax.swing.JFrame; 
 import javax.swing.JLabel; 
 import javax.swing.JPanel; 
 import javax.swing.JTextField; 

 import tutorial1.client.datatypes.Request; 
 import tutorial1.gui.GUIComponent; 

 public class GUIIMpl extends GUIComponent { 

	 @Override 
	 protected void start() { 
		 final JFrame f = new JFrame(); 
		 final JPanel pnl = new JPanel(new GridLayout(3,2)); 
	     pnl.add(new JLabel("Input True? ")); 
	     final JCheckBox tf = new JCheckBox(); 
	     pnl.add(tf); 
	     pnl.add(new JLabel("Output: ")); 
	     final JTextField tf2 = new JTextField(5); 
	     tf2.setEditable(false); 
	     pnl.add(tf2); 
	     final JButton bt = new JButton("Compute!"); 
	     bt.addActionListener(new ActionListener() { 
			 @Override 
			 public void actionPerformed(ActionEvent e) { 
				 Request res = requires().service().compute(new Request(tf.isSelected())); 
				 tf2.setText(""+res.b); 
			 } 
		 }); 
	     pnl.add(bt); 
	     f.getContentPane().add(BorderLayout.NORTH, pnl); 
	     f.pack(); 
	     f.setVisible(true); 
	 } 
 } 
 </pre> 

 h3. Composite Implementation 

 We will now create a component named _CompositeGUIComponent_ similar to _CompositeComponent_ to use this new component. 
 <pre> 
 import tutorial1.client.ClientComponentType 
 import tutorial1.gui.GUIComponent 
 import tutorial1.server.ServerComponentType 

 namespace tutorial1.compositegui { 
	
	 component CompositeGUIComponent { 
		
		 part server: ServerComponentType 
		
		 part client: ClientComponentType { 
			 bind helper to server.service 
		 } 
		
		 part gui: GUIComponent { 
			 bind service to client.service 
		 } 
	 } 
 } 
 </pre> 

 Create an implementation _CompositeGUIImpl_: 
 <pre> 
 package tutorial1.compositegui.impl; 

 import tutorial1.client.ClientComponentType; 
 import tutorial1.client.impl.ClientImpl; 
 import tutorial1.compositegui.CompositeGUIComponent; 
 import tutorial1.gui.GUIComponent; 
 import tutorial1.gui.impl.GUIIMpl; 
 import tutorial1.server.ServerComponentType; 
 import tutorial1.server.impl.ServerImpl; 

 public class CompositeGUIImpl extends CompositeGUIComponent { 

	 @Override 
	 protected ServerComponentType make_server() { 
		 return new ServerImpl(); 
	 } 

	 @Override 
	 protected ClientComponentType make_client() { 
		 return new ClientImpl(); 
	 } 

	 @Override 
	 protected GUIComponent make_gui() { 
		 return new GUIIMpl(); 
	 } 
 } 

 </pre> 

 And the _Application2_ class: 
 <pre> 
 package tutorial1; 

 import tutorial1.compositegui.impl.CompositeGUIImpl; 

 public class Application2 { 

	 public static void main(String[] args) { 
		 new CompositeGUIImpl().newComponent(); 
	 } 

 } 

 </pre> 

 And finally run it to test the GUI. 
 Confirm that when the chekbox is checked, compute fill the the output field with false, and the inverse. 

 h2. Conclusion 

 The tutorial for SpeADL⁻ finishes here. 

 h1. Wiki Page Resources