code: package cnr.rubicon.cml;
  
  //
  //  Connectionless.java
  //  RUBICON src
  //
  //  Created by Claudio Vairo on 10/04/13.
  //  Copyright (c) 2013 ISTI-CNR. All rights reserved.
  //
  
  import cnr.rubicon.migFiles.AppMsg;
  import cnr.rubicon.migFiles.LearningNotificationMsg;
  import ucd.rubicon.network.RubiconAddress;
  
  public class Connectionless {
  
  	private TransportMD tmd;
      private RubiconAck rack;
  	
      //notification to Control layer
      private ReceiveConlessControlListener receiveConlessControlListener;
      //notification to Learning layer
      private ReceiveConlessLearningListener receiveConlessLearningListener;
      
      
      //set the Listener for the event reception of a Control layer message
      public void setOnReceiveConlessControlMessage(ReceiveConlessControlListener listener) {
      	receiveConlessControlListener = listener;
      }
      
      //set the Listener for the event reception of a Learning message
      public void setOnReceiveConlessLearningMessage(ReceiveConlessLearningListener listener) {
      	receiveConlessLearningListener = listener;
      }
      
      
      /*********** START CODE CLAUDIO: check if this solution is good ******************/
      private static Connectionless connless;
      
      public static synchronized Connectionless getConnectionless() {
      	if(connless == null) {
      		connless = new Connectionless();
      	}
      	return connless;
      }
      /*********** END CODE CLAUDIO: check if this solution is good ******************/
      
      /*********** START CODE CLAUDIO: test with Davide TO BE REMOVED ******************/
      //public Network getNetwork() {
      //	return tmd.getNetwork();
      //}
      /*********** END CODE CLAUDIO: test with Davide TO BE REMOVED ******************/
      
      
      //task that prepare the ack message and call the Rubicon_Ack.send_ack
      private void sendAck(short ack_compid, int ack_seqnum, RubiconAddress ack_dest) {
          AppMsg ackmsg = new AppMsg();
          //prepare the learning_notification_msg_t containing the sequence number and the code of error
          LearningNotificationMsg ackpayload = new LearningNotificationMsg();
          ackpayload.set_type(Definitions.AM_LEARNING_NOTIFICATION_MSG);
          ackpayload.set_seq_num(ack_seqnum);
          ackpayload.set_ack(Definitions.ACK_SUCCESS);
  
          //copy the learning_notification_msg_t in the payload of the ackmsg
          ackmsg.set_payload(ackpayload.dataGet());
          //call the send_ack. the size is the size of the seqnum
          rack.send_ack(ack_dest, ackmsg.dataGet(), (short)ackpayload.dataLength(), false, ack_compid);
      }
      
      
  	public Connectionless() {
  		tmd = TransportMD.getTransportMD();
          rack = RubiconAck.getRubiconAck();
          
          tmd.setOnReceiveTransportConnlessListener(new ReceiveTransportConnlessListener() {
  			@Override
  			public void onReceiveTransportConnlessMessage(RubiconAddress sender, byte[] payload, short nbytes, byte reliable, int seqnum) {
  				//System.out.println("onReceiveTransportConnlessMessage invoked");
                  
                  //set the size of the payload except the comp_id
                  short len = (short)(nbytes - 1);
                  //extract the Application comp_id from the first byte of the payload
                  byte comp_id = payload[0];
  
                  //copy the remain part of the payload (just the payload) in a new array to forward to the upper layer
                  byte[] app_payload = new byte[len];
                  for(int i = 0; i < len; i++) {
                      app_payload[i] = payload[i+1];
                  }
                  
                  if(reliable == 1) {
                      //send back the ack
                  	sendAck((short)comp_id, seqnum, sender);
                  }
                  
                  //check to which Application-level component the message has to be forwarded
                  switch(comp_id) {
                      case Definitions.CONTROL_LAYER:
                          if(receiveConlessControlListener!=null) {
                              //signal the reception of the message to the Control Layer component through the listener
                              System.out.println("Received a msg, forwarding to CONTROL LAYER");
                              receiveConlessControlListener.onReceiveConlessControlMessage(sender, app_payload, len);
                          }
                          break;
                          
                      case Definitions.LEARNING:
                          if(receiveConlessLearningListener!=null) {
                              //signal the reception of the message to the Leraning Layer component through the listener
                              receiveConlessLearningListener.onReceiveConlessLearningMessage(sender, app_payload, len);
                          }
                          break;
                  }
                  
  			}
  		});
          
  	}
  	
  	//add the Application ID (comp_id) to the payload and forwards the new payload to the Network
      public synchronized int send(RubiconAddress dest, byte[] payload, short nbytes, boolean reliable, short comp_id) {
  		int seq_num;
          //set the new size of the payload
          short len = (short)(nbytes + 1);
          //fill the second field of the payload with the APP_ID. The Application already allocated the space for this field.
  		payload[1] = (byte)comp_id;
  		
          //call the TransportMD.send with the new payload and the new size
          seq_num = tmd.send(dest, payload, len, reliable, Definitions.CONNLESS);
  		
  		return seq_num;
  
  	}
  }
  