Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Révision 7

Révision 6 (Anonyme, 14/10/2014 15:49) → Révision 7/37 (Anonyme, 14/10/2014 15:49)

h1. SpeADL for Dynamic Architectures Tutorial 

 {{>toc}} 

 This is a tutorial for SpeADL: understanding ecosystems and species, defining a simple ecosystem, composing species together with uses. 

 h2. Objectives 

 The objective of this tutorial to understand the abstractions of species and uses. 

 We will create a Logging ecosystem that contains Logger species. 
 Then we will create a Banking ecosystem that contains Account species that need to log what happens. 
 Finally we will create a Bank ecosystem that compose Account species with Logger species thanks to the use abstraction. 

 h2. Prerequisites 

 It is needed to understand the content of the [[SpeADL Minus Tutorial|SpeADL⁻ tutorial]] before doing this one. 

 h2. Creating a New Project and Organisation 

 Create a Java project. 
 We will use again an organisation of the package and namespaces as explained in [[MAY Best Practices#Project Organisation|this best practice]]. 

 h2. The Logging Ecosystem 

 Logging will be an ecosystem, and its particularity is that it will be able to create Loggers: while logging is the subsystem responsible of all logging, each logger will be responsible of logging one particular aspect of the system identified by a _name_. 
 We will have multiple implementation for the Logging ecosystem: 
 * One with only one file where to log with each line prepended with the name. 
 * One with one file per Logger all in the same directory. 

 h3. Organisation 

 Create the following hierarchy of packages: 
 * tutorial2.logging 
 ** impl 
 ** interfaces 

 h3. Defining the Ecosystem and the Species 

 Create a SpeADL file named _filesystem.speadl_ in the package _tutorial2.filesystem_. 

 Define in it the ecosystem and the species in the right namespace as well as the needed interface: 
 <pre> 
 import tutorial2.filesystem.interfaces.ILog 

 namespace tutorial2.filesystem { 
	
	 ecosystem Logging { 
		 species Logger(name: String) { 
			 provides log: ILog 
		 } 
	 } 
	
 } 
 </pre> 

 <pre> 
 package tutorial2.filesystem.interfaces; 

 public interface ILog { 

	 public void addLine(String line); 
 } 
 </pre> 

 h3. Implementing the Ecosystem and the Species, First One 

 Create a new Java class in _tutorial2.logging.impl_ named _LoggingImplOne_ that extends _Logging_, that takes the a _File_ as a parameter to the constructor to store the logs, and resolve the error with the Quick Fixes of Eclipse: 
 <pre> 
 package tutorial2.logging.impl; 

 import java.io.File; 
 import java.io.FileNotFoundException; 
 import java.io.FileWriter; 
 import java.io.IOException; 
 import java.io.PrintWriter; 

 import tutorial2.logging.Logging; 

 public class LoggingImplOne extends Logging { 

	 private PrintWriter logWriter; 
	
	 public LoggingImplOne(File logFile) { 
		 // if an exception happens, nothing can be done about it 
		 // we just let logStream be null and 
		 // the operations of logging won't be done 
		 try { 
			 this.logWriter = new PrintWriter(new FileWriter(logFile), true); 
		 } catch (FileNotFoundException e) { 
			 System.err.println("An error happened with the file, nothing will be logged."); 
			 this.logWriter = null; 
		 } catch (IOException e) { 
			 System.err.println("An error happened with the file, nothing will be logged."); 
			 this.logWriter = null; 
		 } 
	 } 
	
	 @Override 
	 protected Logger make_Logger(String name) { 
		 // TODO Auto-generated method stub 
		 return null; 
	 } 
 } 
 </pre> 

 As we can see, the species we defined needs to be implemented and this implementation needs to be returned by the method _Logger make_Logger(String name)_. 

 Let's define an inner class inside _LoggingImplOne_ to do that, it will take as a parameter to the constructor the _name_ of the Logger and that will exploit the _logWriter_ to do the actual logging. 
 <pre> 
 public class LoggingImplOne extends Logging { 

	 private PrintWriter logWriter; 
	
	 // ... 
	
	 @Override 
	 protected Logger make_Logger(String name) { 
		 return new LoggerImpl(name); 
	 } 
	
	 private class LoggerImpl extends Logger implements ILog { 

		 private final String name; 
		
		 public LoggerImpl(String name) { 
			 this.name = name; 
		 } 
		
		 @Override 
		 protected ILog make_log() { 
			 return this; 
		 } 

		 @Override 
		 public void addLine(String line) { 
			 if (logWriter != null) { 
				 logWriter.println("["+name+"] "+ line); 
			 } 
		 } 
	 } 
 } 
 </pre> 

 We now have a complete implementation for the Logging ecosystem. 
 Let's test it with a very simple program, for that we will subclass _LoggingImplOne_ in _tutorial2.logging.tests_, create some Logger in its *start()* method and instantiate it: 
 <pre> 
 package tutorial2.logging.tests; 

 import java.io.File; 

 import tutorial2.logging.impl.LoggingImplOne; 

 public class LoggingImplOneTest extends LoggingImplOne { 

	 public LoggingImplOneTest(File logFile) { 
		 super(logFile); 
	 } 

	 @Override 
	 protected void start() { 
		 // create new Loggers 
		 Logger.Component l1 = newLogger("a"); 
		 Logger.Component l2 = newLogger("b"); 
		 Logger.Component l3 = newLogger("c"); 
		 // log things to them 
		 l1.log().addLine("1 a says hi"); 
		 l1.log().addLine("2 test test"); 
		 l2.log().addLine("3 b says hoy"); 
		 l1.log().addLine("4 blabla"); 
		 l3.log().addLine("5 hop"); 
	 } 
	
	 public static void main(String[] args) { 
		 new LoggingImplOneTest(new File("/tmp/tutorial2-logging-test.txt")).newComponent(); 
		
	 } 
 } 
 </pre> 

 Execute it and confirm that the file _/tmp/tutorial2-logging-test.txt_ contains the following: 
 <pre> 
 [a] 1 a says hi 
 [a] 2 test test 
 [b] 3 b says hoy 
 [a] 4 blabla 
 [c] 5 hop 
 </pre> 

 h3. Implementing the Ecosystem and the Species, Second One 

 We can now define a second implementation that stores the logs of each Logger in its own file: 
 <pre> 
 package tutorial2.logging.impl; 

 import java.io.File; 
 import java.io.FileNotFoundException; 
 import java.io.FileWriter; 
 import java.io.IOException; 
 import java.io.PrintWriter; 

 import tutorial2.logging.Logging; 
 import tutorial2.logging.interfaces.ILog; 

 public class LoggingImplTwo extends Logging { 

	 private final File logDir; 

	 public LoggingImplTwo(File logDir) { 
		 this.logDir = logDir; 
		 this.logDir.mkdirs(); 
	 } 
	
	 @Override 
	 protected Logger make_Logger(String name) { 
		 return new LoggerImpl(new File(logDir, name+".txt")); 
	 } 
	
	 private class LoggerImpl extends Logger implements ILog { 

		 private PrintWriter logWriter; 
		
		 public LoggerImpl(File logFile) { 
			 // if an exception happens, nothing can be done about it 
			 // we just let logStream be null and 
			 // the operations of logging won't be done 
			 try { 
				 this.logWriter = new PrintWriter(new FileWriter(logFile), true); 
			 } catch (FileNotFoundException e) { 
				 System.err.println("An error happened with the file, nothing will be logged."); 
				 this.logWriter = null; 
			 } catch (IOException e) { 
				 System.err.println("An error happened with the file, nothing will be logged."); 
				 this.logWriter = null; 
			 } 
		 } 
		
		 @Override 
		 protected ILog make_log() { 
			 return this; 
		 } 

		 @Override 
		 public void addLine(String line) { 
			 if (logWriter != null) { 
				 logWriter.println(line); 
			 } 
		 } 
	 } 
 } 
 </pre> 

 That can be tested with the following subclass: 
 <pre> 
 package tutorial2.logging.tests; 

 import java.io.File; 

 import tutorial2.logging.impl.LoggingImplTwo; 

 public class LoggingImplTwoTest extends LoggingImplTwo { 

	 public LoggingImplTwoTest(File logDir) { 
		 super(logDir); 
	 } 
	
	 @Override 
	 protected void start() { 
		 // create new Loggers 
		 Logger.Component l1 = newLogger("a"); 
		 Logger.Component l2 = newLogger("b"); 
		 Logger.Component l3 = newLogger("c"); 
		 // log things to them 
		 l1.log().addLine("1 a says hi"); 
		 l1.log().addLine("2 test test"); 
		 l2.log().addLine("3 b says hoy"); 
		 l1.log().addLine("4 blabla"); 
		 l3.log().addLine("5 hop"); 
	 } 
	
	 public static void main(String[] args) { 
		 new LoggingImplTwoTest(new File("/tmp/tutorial2-logging2-test/")).newComponent(); 
	 } 
 } 
 </pre> 

 Execute it and confirm that the _/tmp/tutorial2-logging2-test/_ directory contains one file per Logger with the correct content.