Developer Guide

Generated code

Root Class

A UML Class defined as <<Root>> represents the system managing the different components.

It allows to generate the code to initialize the applicative system:

Component Class

Overview

PENDING

Some details

A component is modeled as a UML Class with a UML Port at least and it is generated as a Java Class.

A component (Java Class) has to implement the services provided by its ports (through the interfaces).

The internal interface "SMState" lists, as method signatures, the set of the signals that the component may receive. These are the signatures of the receptions from the Asynchronous interfaces used by the component. For example:

interface SMState {
	void orbit_changemode_aoc();

	void orbit_changemode_groundnav();

	void orbit_changemode_navigation();

	void orbit_changemode_safe();

	void orbit_changemode_test();

	void aoc_new_slot(double start_time, double end_time);

	void orbit_periodic_treatments();

	void loadContext(int context);

	SMState enterHState();

	void exitToState(SMState s);
}

The handlers are methods in which the method with the same, from the "currentState" object of "StateMachine", is called.

So, one method, per reception from the Asynchronous interfaces used by the component, is generated. For example:

public void loadContext(int context) {
	StateMachine.current_state.loadContext(context);
}
public void orbit_periodic_treatments() {
	StateMachine.current_state.orbit_periodic_treatments();
}
public void aoc_new_slot(double start_time, double end_time) {
	StateMachine.current_state.aoc_new_slot(start_time, end_time);
}

The "StateMachine_States" abstract class implements the "SMState" interface with an empty method for each signature. So, this enables to get through events when there is no action for these ones (no outgoing transition on these events).

abstract class StateMachine_States implements SMState {
		
	public void orbit_changemode_aoc() {
	}
			
	public void orbit_changemode_groundnav() {
	}
}

The "PortBuffer" is used to store the order of arrival of requests.

PortBuffer pbuffer = new PortBuffer(20);

The size is defined as specified in Asynchronous_communication section.

In the "body()" method, if the "pBuffer" is not empty then there is a request on one port at least. The call to "pBuffer.get()" enables to get the related port. At last, "invokeNextOperation()" enables to execute the first call of service on this port.

Communication layer

The root class uses some services from the communication layer to install the communication architecture before running the applicative system. This is made in the "makeConnection()" method.

Synchronous communication

The synchronous services provided by a component are defined in interfaces (modeled as simple UML Interfaces).

These components are classes which implement these interfaces. Each UML Port uses one of these interfaces to provide the related services.

The user (caller) component can access to these services through these ports.

When the "class2" component instance wishes to call "class3" to invoke the service "monService1" through the port "monPort2", here is the sequence which is processed:

Initialization from Root Class

public static CommunicationLayer communicationLayer = new CommunicationLayer();

public static Class2 class2 = new Class2();
public static Class3 class3 = new Class3();

public static void init(int freq_OBC) {
	class2.initPortsGenerator("class2", communicationLayer);
	class3.initPortsGenerator("class3", communicationLayer);

	makeConnections();
	
	start_all();
}
	
private static void makeConnections() {
	communicationLayer.setSynchronousConnection("class3:monPort1", "class2:monPort2");
}

public static void start_all() {
	class2.start_all();
	class3.start_all();
}

Code for user (output) ports

A Java class is generated per user port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_UserSync

public class Class2_monPort2_UserSync implements InterfaceSynchronous {

	String ident;
	InterfaceSynchronous_monService1_Int_Params monService1IntParams = new InterfaceSynchronous_monService1_Int_Params(false);
	InterfaceSynchronous_monService2_Params monService2Params = new InterfaceSynchronous_monService2_Params(false);
	InterfaceSynchronous_monService1_BooleanInt_Params monService1BooleanIntParams = new InterfaceSynchronous_monService1_BooleanInt_Params(false);
	
	CommunicationLayer communicationLayer;

	public Class2_monPort2_UserSync(String ident, CommunicationLayer communicationLayer) {
		this.ident = ident;
		this.communicationLayer = communicationLayer;
	}

	public void monService1(int param1) throws ServiceNotFoundException {
		monService1IntParams.param1 = param1;
		communicationLayer.callSynchronous("monService1int", ident, monService1IntParams);
		
	}
		
	public void monService2(SharedData param) throws ServiceNotFoundException {
		monService2Params.param = param;
		communicationLayer.callSynchronous("monService2SharedData", ident, monService2Params);
		
	}
		
	public void monService1(int param1, boolean param2) throws ServiceNotFoundException {
		monService1BooleanIntParams.param1 = param1;
		monService1BooleanIntParams.param2 = param2;
		communicationLayer.callSynchronous("monService1int_boolean", ident, monService1BooleanIntParams);
		
	}
		
}

Code for provider (input) ports

A Java class is generated per provider port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_ProviderSync

public class Class3_monPort1_ProviderSync implements PortProviderSync {

	InterfaceSynchronous provider;
	String ident;
	
	CommunicationLayer communicationLayer;

	public Class3_monPort1_ProviderSync(InterfaceSynchronous provider, String ident, CommunicationLayer communicationLayer) {
		this.provider = provider;
		this.ident = ident;
		communicationLayer.registerSynchronousProviderPort(ident, this);
		this.communicationLayer = communicationLayer;
	}

	public void monService1(InterfaceSynchronous_monService1_Int_Params param) {
		provider.monService1(param.param1);
	}		
	public void monService2(InterfaceSynchronous_monService2_Params param) {
		provider.monService2(param.param);
	}		
	public void monService1(InterfaceSynchronous_monService1_BooleanInt_Params param) {
		provider.monService1(param.param1, param.param2);
	}		
	public Object invoke(String op, ParameterSet param) throws ServiceNotFoundException {
		if (op.equals("monService1int")) {
			this.monService1((InterfaceSynchronous_monService1_Int_Params) param);
		} else if (op.equals("monService2SharedData")) {
			this.monService2((InterfaceSynchronous_monService2_Params) param);
		} else if (op.equals("monService1int_boolean")) {
			this.monService1((InterfaceSynchronous_monService1_BooleanInt_Params) param);
		} else {
			throw new ServiceNotFoundException();
		}
		return null;
	}
}

Asynchronous communication

Unlike the synchronous communication, the call requests are recorded in 2 buffers, in the provider port:

The call is handled when the component thread unstacks the buffer.

The asynchronous services provided by a component are defined in interfaces (modeled as UML Interfaces with the stereotype <<Asynchronous>>).

The provider port has to precise the max number of messages to be able to store.

When the "class2" component instance wishes to call "class3", the behavior is the same as the synchronous communication unless the communication layer stores the data in the buffers of the provider target port and the called services return nothing.

The provider port defines several methods:

The size of the "MBuffer" comes from the property in the stereotype <<LossyBuffer>> if applied on it or is computed by the generator (according to the activation periods of the related component instance and the user component instances sending messages) if the stereotype <<ExactBuffer>> is applied.

The size of the "ArgsBuffer" is the size of the largest "ParameterSet" used within the port (along the receptions of the interface) * the max number of messages to be able to store.

Also, the provider port defines a "PortBuffer" to centralize the requests on the whole owning component instance. Its size is the sum of the size of the "Mbuffers" of every ports of the component.

Initialization from Root Class

It is the same code as synchronous communication unless makeConnections() method.

private static void makeConnections() {
	communicationLayer.setAsynchronousConnection("class3:monPort1", "class2:monPort2");
}

Code for user (output) ports

A Java class is generated per user port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_UserAsync

public class Class2_monPort2_UserAsync implements InterfaceAsynchronous {

	String ident;
	String sender;
	InterfaceAsynchronous_monService1_Params monService1Params = new InterfaceAsynchronous_monService1_Params(false);
	InterfaceAsynchronous_monService2_Params monService2Params = new InterfaceAsynchronous_monService2_Params(false);
	ArgsBuffer argsBuffer = new ArgsBuffer(21);
	CommunicationLayer communicationLayer;
	int signalPriority = 1;

	public Class2_monPort2_UserAsync(String ident, String sender, CommunicationLayer communicationLayer) {
		this.ident = ident;
		this.sender = sender;
		this.communicationLayer = communicationLayer;
	}

	public InterfaceAsynchronous setSignalPriority(int priority) {
		this.signalPriority = priority;
		return this;
	}

	public void monService1(int param1, int param2) throws ServiceNotFoundException {
		monService1Params.param1 = param1;
		monService1Params.param2 = param2;
		argsBuffer.dequeue(argsBuffer.getUsed());
		monService1Params.writeObject(argsBuffer);
		communicationLayer.callAsynchronous("monService1int_int", ident, sender, argsBuffer, this.signalPriority);
		this.setSignalPriority(1);
	}
		
	public void monService2(SharedData param1) throws ServiceNotFoundException {
		monService2Params.param1 = param1;
		argsBuffer.dequeue(argsBuffer.getUsed());
		monService2Params.writeObject(argsBuffer);
		communicationLayer.callAsynchronous("monService2SharedData", ident, sender, argsBuffer, this.signalPriority);
		this.setSignalPriority(1);
	}
}

Code for provider (input) ports

A Java class is generated per provider port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_ProviderAsync

public class Class3_monPort1_ProviderAsync implements PortProviderAsync {

	InterfaceAsynchronous provider;
	String ident;
	Object thread;
	PortBuffer pbuff;
	MBuffer mbuffer;
	ArgsBuffer argsBuffer;
	int max_size_parameter_set = 21;
	InterfaceAsynchronous_monService1_Params monService1Params = new InterfaceAsynchronous_monService1_Params(true);
	InterfaceAsynchronous_monService2_Params monService2Params = new InterfaceAsynchronous_monService2_Params(true);
	CommunicationLayer communicationLayer;
	CommunicationExceptionInterface exceptionCatcher;

	public Class3_monPort1_ProviderAsync(InterfaceAsynchronous provider, String ident, int size, Object thread, PortBuffer pbuff, CommunicationLayer communicationLayer, CommunicationExceptionInterface exceptionCatcher) {
		this.provider = provider;
		this.ident = ident;
		communicationLayer.registerAsynchronousProviderPort(ident, this);
		mbuffer = new MBuffer(size);
		argsBuffer = new ArgsBuffer(max_size_parameter_set * size);
		this.thread = thread;
		this.pbuff = pbuff;
		this.communicationLayer = communicationLayer;
		this.exceptionCatcher = exceptionCatcher;
	}

	public boolean empty() { 
		return mbuffer.empty(); 
	}
	
	public boolean full() { 
		return mbuffer.full(); 
	}

	public void invokeNextOperation() throws ServiceNotFoundException {
		if (mbuffer.empty()) return;
		String op = mbuffer.get();
		if (op.equals("monService1int_int")) {
			monService1Params.readObject(argsBuffer);
			provider.monService1(monService1Params.param1, monService1Params.param2);
		} else if (op.equals("monService2SharedData")) {
			monService2Params.readObject(argsBuffer);
			provider.monService2(monService2Params.param1);
		} else {
			throw new ServiceNotFoundException();
		}
	}

	public void store(String service, ArgsBuffer params, int priority) {
		synchronized (thread) {
			if (pbuff.full() || mbuffer.full() || !argsBuffer.check(params.getUsed())) {
				exceptionCatcher.catchCommunicationException(service, params);
			}
			else {
				if (pbuff.empty()) {
					thread.notify();
				}
				pbuff.put(this, priority);
				int offset = mbuffer.put(service, priority, params.getUsed());
				argsBuffer.copy(params, offset);
			}
		}
	}
}

Event data communication

The "EventData" ports are used to communicate data between different components from an asynchronous way. These ports allow an application which modifies one of these data to communicate the new value to other parts of the system.

The messages are defined in "EventData" UML Interfaces as UML Receptions. Each UML Reception has one parameter only, corresponding to the shared data.

A user (output) port uses this kind of interface and it can be connected to several recipients. It implements a method for each UML Reception of the interface with the kind of data to send as parameter. The "sendEventData()" service from the communication layer is used to send these data. It contains a "ArgsBuffer" to serialize the data to send. The communication layer retrieves the every target ports and it stores the message in the buffer of the used service.

A provider (input) port implements this kind of interface and it owns a buffer ("ArgsBuffer") per provided service. So, a <<EventDataBuffer>> stereotype has to be applied on each UML Reception. It contains a "size" attribute to define the size of the buffer.

The provider port owns 3 methods for each service:

Also, it owns a "store()" method to store new data in the buffer, with a string for the id of the message and an object for the data, as parameters. According to the message, this method serializes the object and it stores it in the related buffer.

Initialization from Root Class

It is the same code as synchronous communication unless makeConnections() method.

private static void makeConnections() {
	String[] class2Port4Receivers = new String[2];
	class2Port4Receivers[0] = "class1:Port3";
	class2Port4Receivers[1] = "class3:Port5";
	communicationLayer.setEventDataConnection("class2:Port4", class2Port4Receivers);
	communicationLayer.registerEventDataReceiverPort(class2Port4Receivers[0], class1.getPort3());
	communicationLayer.registerEventDataReceiverPort(class2Port4Receivers[1], class3.getPort5());
}

Code for user (output) ports

A Java class is generated per user port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_EmitterEventData

public class Class2_Port4_EmitterEventData {

	String ident;
	String sender;
	ArgsBuffer argsBuffer = new ArgsBuffer(21);
	CommunicationLayer communicationLayer;

	public Class2_Port4_EmitterEventData(String ident, String sender, CommunicationLayer communicationLayer) {
		this.ident = ident;
		this.sender = sender;
		this.communicationLayer = communicationLayer;
	}

	public void Signal3(int params) throws ServiceNotFoundException {
		argsBuffer.dequeue(argsBuffer.getUsed());
		argsBuffer.writeInteger(params);
		communicationLayer.sendEventData("Signal3", ident, sender, argsBuffer);
	}
		
	public void Signal2(SharedData params) throws ServiceNotFoundException {
		argsBuffer.dequeue(argsBuffer.getUsed());
		params.writeObject(argsBuffer);
		communicationLayer.sendEventData("Signal2", ident, sender, argsBuffer);
	}
		
}

Code for provider (input) ports

A Java class is generated per provider port, named according to this pattern:

[name of the component definition owning the port]_[name of the port]_ReceiverEventData

public class Class1_Port3_ReceiverEventData implements EventDataPort {

	String ident;
	ArgsBuffer Signal3Buffer;
	ArgsBuffer Signal2Buffer;
	int Signal3Param;
	SharedData Signal2Param;
	CommunicationLayer communicationLayer;

	public Class1_Port3_ReceiverEventData(String ident, CommunicationLayer communicationLayer) {
		this.ident = ident;
		Signal3Buffer = new ArgsBuffer(4);
		Signal2Buffer = new ArgsBuffer(21);
		Signal2Param = new SharedData();
		this.communicationLayer = communicationLayer;
	}

	/**
	 * Delinearization of data if received.
	 * 
	 * @return data delinearized or stocked data by default
	 */
	public int getSignal3() {	
		if (this.hasReceivedSignal3()) {
			synchronized (Signal3Buffer) {	
				Signal3Param = Signal3Buffer.readInteger();
			}
		}
		return Signal3Param;
	}
	/**
	 * @return stocked data
	 */
	public int getPreviousSignal3() {	
		return Signal3Param;
	}
	/**
	 * Test if data has been received in buffer.
	 * 
	 * @return true if buffer contains data
	 */
	public boolean hasReceivedSignal3() {
		boolean result = false;
		synchronized (Signal3Buffer) {
			result = !Signal3Buffer.check(Signal3Buffer.getSize());
		}
		return result;
	}
	/**
	 * Delinearization of data if received.
	 * 
	 * @return data delinearized or stocked data by default
	 */
	public SharedData getSignal2() {	
		if (this.hasReceivedSignal2()) {
			synchronized (Signal2Buffer) {	
				Signal2Param.readObject(Signal2Buffer);
			}
		}
		return Signal2Param;
	}
	/**
	 * @return stocked data
	 */
	public SharedData getPreviousSignal2() {	
		return Signal2Param;
	}
	/**
	 * Test if data has been received in buffer.
	 * 
	 * @return true if buffer contains data
	 */
	public boolean hasReceivedSignal2() {
		boolean result = false;
		synchronized (Signal2Buffer) {
			result = !Signal2Buffer.check(Signal2Buffer.getSize());
		}
		return result;
	}

	public void store(String sig, ArgsBuffer param) throws ServiceNotFoundException {
		if (sig.equals("Signal3")) {
			synchronized (Signal3Buffer) {
				if (!Signal3Buffer.check(param.getUsed())) {
					Signal3Buffer.dequeue(param.getUsed());
				}
				Signal3Buffer.copy(param);
			}
		} else if (sig.equals("Signal2")) {
			synchronized (Signal2Buffer) {
				if (!Signal2Buffer.check(param.getUsed())) {
					Signal2Buffer.dequeue(param.getUsed());
				}
				Signal2Buffer.copy(param);
			}
		} else {
			throw new ServiceNotFoundException();
		}
	}	
}

Same thing for the Port5 from Class3.

Use of Ethernet protocol

The communication framework brings some API to manage the communication betwwen instances of communication layers.

A class implementing the "ComProtocol" interface has to be generated for each component communicating through Ethernet. It contains :

Initialization from root emitter class

public static void init(int freq_OBC) {
	<emitter component>.initPortsGenerator(<emitter component name>, communicationLayer);		
	
	communicationLayer.registerComProtocol(<emitter component name>, new EthernetComClass2(communicationLayer));
		
	makeConnections();
		
	start_all();
}

private static void makeConnections() {
	String[] <receiver port ids> = new String[0];

	communicationLayer.setSynchronousConnection(<receiver port id>, <emitter port id>);

	communicationLayer.setAsynchronousConnection(<receiver port id>, <emitter port id>);

	communicationLayer.setEventDataConnection(<emitter port id>, <receiver port ids>);

	String[] <receiver component names> = new String[2];
	class2Port4DestComp[0] = <receiver component name 1>;
	class2Port4DestComp[1] = <receiver component name 2>;
	...
	communicationLayer.setComponentMap(<emitter port id>, <receiver component names>);
}

Initialization from root receiver class

public static void init(int freq_OBC) {
	class1.initPortsGenerator(<receiver component name>, communicationLayer);
	
	communicationLayer.registerComProtocol(<receiver component name>, new EthernetCom<receiver component name>(communicationLayer));
		
	makeConnections();

	start_all();
}

	
private static void makeConnections() {
	communicationLayer.setSynchronousConnection(<current receiver port id>, <emitter port id>);
}

private static void makeConnections() {	
	communicationLayer.setAsynchronousConnection(<current receiver port id>, <emitter port id>);
}

	
private static void makeConnections() {
	String[] <receiver port id> = new String[1];
	<receiver port id>[0] = <current receiver port id>;
	communicationLayer.setEventDataConnection(<emitter port id>, <receiver port id>);
	communicationLayer.registerEventDataReceiverPort(<receiver port id>, <receiver port>);
}

Example on the EventData use case

"Ma conf" on Connector1 and Connector2
"Container A" contains "class1"
"Container B" contains "class2"
"Container C" contains "class3"
Initialization from the emitter (AppliB containing class2)
public static void init(int freq_OBC) {
	class2.initPortsGenerator("class2", communicationLayer);		

	communicationLayer.registerComProtocol("class2", new EthernetComClass2(communicationLayer));

	makeConnections();
	
	start_all();
}
	
private static void makeConnections() {
	String[] class2Port4Receivers = new String[0];
	communicationLayer.setEventDataConnection("class2:Port4", class2Port4Receivers);
	String[] class2Port4DestComp = new String[2];
	class2Port4DestComp[0] = "class1";
	class2Port4DestComp[1] = "class3";
	communicationLayer.setComponentMap("class2:Port4", class2Port4DestComp);
}

Initialization from one receiver (AppliA containing class1)
public static void init(int freq_OBC) {	
	class1.initPortsGenerator("class1", communicationLayer);
	
	communicationLayer.registerComProtocol("class1", new EthernetComClass1(communicationLayer));

	makeConnections();

	start_all();
}
	
private static void makeConnections() {
	String[] class2Port4Receivers = new String[1];
	class2Port4Receivers[0] = "class1:Port3";
	communicationLayer.setEventDataConnection("class2:Port4", class2Port4Receivers);
	communicationLayer.registerEventDataReceiverPort(class2Port4Receivers[0], class1.getPort3());
}

EthernetCom for the class2 emitter component
public class EthernetComClass2 implements ComProtocol {

	private InetAddress addrClass1;
	private Socket socketClass1client ;
	static final int class1Port = 27;
	private BufferedOutputStream outClass1 ;
	private InetAddress addrClass3;
	private Socket socketClass3client ;
	static final int class3Port = 29;
	private BufferedOutputStream outClass3 ;

	static final int serverPort = 28;
	ArgsBuffer header = new ArgsBuffer(31);
	
	public EthernetComClass2(CommunicationLayer communicationLayer) {
		new ServerThread(serverPort, communicationLayer) ;
		try {
			addrClass1 = InetAddress.getByName("127.0.0.1");
			addrClass3 = InetAddress.getByName("127.0.0.1");

			for (int i = 0 ; i < 10 ; i++){
				try {
					if (socketClass1client == null) {
						socketClass1client = new Socket(addrClass1, class1Port);
					}
					if (socketClass3client == null) {
						socketClass3client = new Socket(addrClass3, class3Port);
					}
					break ;
				} catch (IOException e) {
					if (i == 9){
						e.printStackTrace();
						throw (new RuntimeException());
					} else {
						try {
							Thread.sleep((i+1)*5000);
						} catch (InterruptedException e1) {
							e1.printStackTrace();
						}
					}
				}
			}
			outClass1 = new BufferedOutputStream(socketClass1client.getOutputStream());
			outClass3 = new BufferedOutputStream(socketClass3client.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void sendFrame (String dest, String ident, String service, ArgsBuffer params, int priority){
		header.writeString(ident);
		header.writeString(service);
		header.writeInteger(priority);
		if (params != null) {		
			header.writeInteger(params.getUsed());
		} else {
			header.writeInteger(0);
		}
		int bufferSize;
		if (dest.equals("class1")){
			try {
				outClass1.write(header.getUsed());
				bufferSize = header.getUsed();
				while (header.getUsed() > 0){
					outClass1.write(header.readByte());
				}
				bufferSize = params.getUsed();
				for (int i = 0; i < bufferSize; i++){
					outClass1.write(params.readByteAt(i));
				}
				outClass1.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}			
		}
		if (dest.equals("class3")){
			try {
				outClass3.write(header.getUsed());
				bufferSize = header.getUsed();
				while (header.getUsed() > 0){
					outClass3.write(header.readByte());
				}
				bufferSize = params.getUsed();
				for (int i = 0; i < bufferSize; i++){
					outClass3.write(params.readByteAt(i));
				}
				outClass3.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}			
		}
	}
}

EthernetCom for the class1 receiver component
public class EthernetComClass1 implements ComProtocol {


	static final int serverPort = 27;
	ArgsBuffer header = new ArgsBuffer(19);
	
	public EthernetComClass1(CommunicationLayer communicationLayer) {
		new ServerThread(serverPort, communicationLayer) ;
	}
	
	public void sendFrame (String dest, String ident, String service, ArgsBuffer params, int priority){
		header.writeString(ident);
		header.writeString(service);
		header.writeInteger(priority);
		if (params != null) {		
			header.writeInteger(params.getUsed());
		} else {
			header.writeInteger(0);
		}
		int bufferSize;
	}
}

Tooling

Extensibility of the architecture style modeling

PENDING

Extensibility of the architecture style generation

PENDING