added HO and RRMConf NB api
diff --git a/src/main/java/org.onosproject.xran/controller/Controller.java b/src/main/java/org.onosproject.xran/controller/Controller.java
index b5b7f7d..2191f5b 100644
--- a/src/main/java/org.onosproject.xran/controller/Controller.java
+++ b/src/main/java/org.onosproject.xran/controller/Controller.java
@@ -73,7 +73,7 @@
         return b;
     }
 
-    public void start(XranDeviceAgent deviceAgent, XranHostAgent hostAgent, XranControllerImpl.InternalXranPacketAgent packetAgent, int port) {
+    public void start(XranDeviceAgent deviceAgent, XranHostAgent hostAgent, XranPacketProcessor packetAgent, int port) {
         if (isRunning && this.port != port) {
             stop();
             this.deviceAgent = deviceAgent;
diff --git a/src/main/java/org.onosproject.xran/controller/XranController.java b/src/main/java/org.onosproject.xran/controller/XranController.java
index 19b7537..9f2ae7a 100644
--- a/src/main/java/org.onosproject.xran/controller/XranController.java
+++ b/src/main/java/org.onosproject.xran/controller/XranController.java
@@ -16,14 +16,21 @@
 
 package org.onosproject.xran.controller;
 
+import org.onosproject.xran.entities.RnibCell;
+import org.onosproject.xran.entities.RnibLink;
 import org.onosproject.xran.providers.XranDeviceListener;
 import org.onosproject.xran.providers.XranHostListener;
 
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+
 /**
  * Created by dimitris on 7/27/17.
  */
 public interface XranController {
 
+    SynchronousQueue<String> sendHORequest(RnibLink newLink, RnibLink oldLink);
+
     void addListener(XranDeviceListener listener);
 
     void addListener(XranHostListener listener);
@@ -31,4 +38,6 @@
     void removeListener(XranDeviceListener listener);
 
     void removeListener(XranHostListener listener);
+
+    SynchronousQueue<String> sendModifiedRRMConf(RnibCell cell);
 }
diff --git a/src/main/java/org.onosproject.xran/controller/XranControllerImpl.java b/src/main/java/org.onosproject.xran/controller/XranControllerImpl.java
index 36b4c07..a3740bc 100644
--- a/src/main/java/org.onosproject.xran/controller/XranControllerImpl.java
+++ b/src/main/java/org.onosproject.xran/controller/XranControllerImpl.java
@@ -49,17 +49,16 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.xml.bind.DatatypeConverter;
 import java.io.IOException;
 import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.*;
 import java.util.stream.Collectors;
 
 import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.xran.controller.XranChannelHandler.getSctpMessage;
 import static org.onosproject.xran.entities.RnibCell.decodeDeviceId;
 import static org.onosproject.xran.entities.RnibCell.uri;
-import static org.onosproject.xran.entities.RnibUe.UeState;
 import static org.onosproject.xran.entities.RnibUe.hostIdtoMME;
 
 /**
@@ -107,6 +106,8 @@
     private LinkMap linkMap;
     /* MAPS */
     private ConcurrentMap<String, ECGI> legitCells = new ConcurrentHashMap<>();
+    private ConcurrentMap<CRNTI, SynchronousQueue<String>> hoQueue = new ConcurrentHashMap<CRNTI, SynchronousQueue<String>>();
+    private ConcurrentMap<ECGI, SynchronousQueue<String>> RRMCellQueue = new ConcurrentHashMap<ECGI, SynchronousQueue<String>>();
     /* AGENTS */
     private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
     private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
@@ -151,6 +152,28 @@
     }
 
     @Override
+    public SynchronousQueue<String> sendHORequest(RnibLink newLink, RnibLink oldLink) {
+        ECGI newEcgi = newLink.getLinkId().getSourceId(),
+                oldEcgi = oldLink.getLinkId().getSourceId();
+        CRNTI crnti = linkMap.getCrnti(newLink.getLinkId().getDestinationId());
+        ChannelHandlerContext newCtx = cellMap.getCtx(newEcgi),
+                oldCtx = cellMap.getCtx(oldEcgi);
+
+        try {
+            XrancPdu xrancPdu = HandoffRequest.constructPacket(crnti, oldEcgi, newEcgi);
+            newCtx.writeAndFlush(getSctpMessage(xrancPdu));
+            oldCtx.writeAndFlush(getSctpMessage(xrancPdu));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        SynchronousQueue<String> queue = new SynchronousQueue<>();
+        hoQueue.put(crnti, queue);
+
+        return queue;
+    }
+
+    @Override
     public void addListener(XranDeviceListener listener) {
         xranDeviceListeners.add(listener);
     }
@@ -170,6 +193,22 @@
         xranHostListeners.remove(listener);
     }
 
+    @Override
+    public SynchronousQueue<String> sendModifiedRRMConf(RnibCell cell) {
+        ECGI ecgi = cell.getEcgi();
+        ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
+        try {
+            XrancPdu pdu = RRMConfig.constructPacket(cell);
+            ctx.writeAndFlush(getSctpMessage(pdu));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        SynchronousQueue<String> queue = new SynchronousQueue<>();
+        RRMCellQueue.put(ecgi, queue);
+
+        return queue;
+    }
+
     private void restartTimer(RnibUe ue) {
         Timer timer = new Timer();
         ue.setTimer(timer);
@@ -177,7 +216,7 @@
         timer.schedule(new TimerTask() {
             @Override
             public void run() {
-                if (ue.getUeState() == UeState.IDLE) {
+                if (ue.getState() == RnibUe.State.IDLE) {
                     hostAgent.removeConnectedHost(ue);
                     log.info("UE is removed after 10 seconds of IDLE");
                 } else {
@@ -222,8 +261,8 @@
                                             if (conf == null) {
                                                 try {
                                                     ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
-                                                    SctpMessage msg = XranChannelHandler.getSctpMessage(ConfigEncoderDecoder.constructPacket(ecgi));
-                                                    ctx.writeAndFlush(msg);
+                                                    XrancPdu xrancPdu = ConfigEncoderDecoder.constructPacket(ecgi);
+                                                    ctx.writeAndFlush(getSctpMessage(xrancPdu));
                                                 } catch (IOException e) {
                                                     log.error(ExceptionUtils.getFullStackTrace(e));
                                                     e.printStackTrace();
@@ -236,8 +275,7 @@
                                                             getCtx(ecgi);
                                                     XrancPdu xrancPdu = L2MeasConf.constructPacket(ecgi, xranConfig.getL2MeasInterval());
                                                     cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
-                                                    SctpMessage sctpMessage = XranChannelHandler.
-                                                            getSctpMessage(xrancPdu);
+                                                    SctpMessage sctpMessage = getSctpMessage(xrancPdu);
                                                     ctx.writeAndFlush(sctpMessage);
                                                 } catch (IOException e) {
                                                     log.error(ExceptionUtils.getFullStackTrace(e));
@@ -287,11 +325,10 @@
                                             if (ue.getCapability() == null) {
                                                 try {
                                                     ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
-                                                    SctpMessage msg = XranChannelHandler.
-                                                            getSctpMessage(UECapabilityEnq.constructPacket(
-                                                                    primary.getEcgi(),
-                                                                    ue.getRanId()));
-                                                    ctx.writeAndFlush(msg);
+                                                    XrancPdu xrancPdu = UECapabilityEnq.constructPacket(
+                                                            primary.getEcgi(),
+                                                            ue.getRanId());
+                                                    ctx.writeAndFlush(getSctpMessage(xrancPdu));
                                                 } catch (IOException e) {
                                                     log.warn(ExceptionUtils.getFullStackTrace(e));
                                                     e.printStackTrace();
@@ -317,8 +354,7 @@
                                                                 xranConfig.getRxSignalInterval()
                                                         );
                                                         ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
-                                                        SctpMessage msg = XranChannelHandler.getSctpMessage(xrancPdu);
-                                                        ctx.writeAndFlush(msg);
+                                                        ctx.writeAndFlush(getSctpMessage(xrancPdu));
                                                     } catch (IOException e) {
                                                         log.warn(ExceptionUtils.getFullStackTrace(e));
                                                         e.printStackTrace();
@@ -400,7 +436,7 @@
 
                 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
                         .stream()
-                        .map(l -> l.getLinkId().getSource())
+                        .map(l -> l.getLinkId().getSourceId())
                         .collect(Collectors.toSet());
 
                 for (XranHostListener l : xranHostListeners) {
@@ -462,7 +498,7 @@
                     if (xranStore.getCell(ecgi) != null) {
                         CRNTI crnti = ueAdmissionRequest.getCrnti();
                         send_pdu = UEAdmEncoderDecoder.constructPacket(ecgi, crnti);
-                        ctx.writeAndFlush(XranChannelHandler.getSctpMessage(send_pdu));
+                        ctx.writeAndFlush(getSctpMessage(send_pdu));
                     } else {
                         log.warn("Could not find ECGI in registered cells: {}", ecgi);
                     }
@@ -475,9 +511,9 @@
                     RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
                     if (ue != null) {
                         if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
-                            ue.setUeState(UeState.ACTIVE);
+                            ue.setState(RnibUe.State.ACTIVE);
                         } else {
-                            ue.setUeState(UeState.IDLE);
+                            ue.setState(RnibUe.State.IDLE);
                         }
                     }
                     break;
@@ -518,7 +554,7 @@
                     UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
                     RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
                     if (ue != null) {
-                        ue.setUeState(UeState.IDLE);
+                        ue.setState(RnibUe.State.IDLE);
                         restartTimer(ue);
                     }
                     break;
@@ -541,7 +577,7 @@
 
                     send_pdu = BearerEncoderDecoder.constructPacket(ecgi, crnti, erabParams, numErabs);
                     // Encode and send Bearer Admission Response - API ID 9
-                    ctx.writeAndFlush(XranChannelHandler.getSctpMessage(send_pdu));
+                    ctx.writeAndFlush(getSctpMessage(send_pdu));
                     break;
                 }
                 case 10: {
@@ -582,7 +618,7 @@
                     // Encode and send UE CAPABILITY ENQUIRY
                     UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
                     XrancPdu xrancPdu = UECapabilityEnq.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
-                    ctx.writeAndFlush(XranChannelHandler.getSctpMessage(xrancPdu));
+                    ctx.writeAndFlush(getSctpMessage(xrancPdu));
                     break;
                 }
                 case 13: {
@@ -599,6 +635,40 @@
 
                     //14, 15, 16 are handoff
                 }
+                case 15: {
+                    HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
+
+                    try {
+                        hoQueue.get(hoFailure.getCrnti())
+                                .put("Hand Over Failed with cause: " + hoFailure.getCause());
+                    } catch (InterruptedException e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        e.printStackTrace();
+                    } finally {
+                        hoQueue.remove(hoFailure.getCrnti());
+                    }
+                    break;
+                }
+                case 16: {
+                    HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
+
+                    RnibLink oldLink = linkMap.get(hoComplete.getEcgiS(), hoComplete.getCrntiNew()),
+                            newLink = linkMap.get(hoComplete.getEcgiT(), hoComplete.getCrntiNew());
+
+                    oldLink.setType(RnibLink.Type.NON_SERVING);
+                    newLink.setType(RnibLink.Type.SERVING_PRIMARY);
+
+                    try {
+                        hoQueue.get(hoComplete.getCrntiNew())
+                                .put("Hand Over Completed");
+                    } catch (InterruptedException e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        e.printStackTrace();
+                    } finally {
+                        hoQueue.remove(hoComplete.getCrntiNew());
+                    }
+                    break;
+                }
                 case 18: {
                     // Decode RX Sig Meas Report.
                     RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
@@ -666,7 +736,7 @@
                             log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
                         }
                     });
-
+                    break;
                 }
                 case 21: {
                     RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
@@ -723,6 +793,19 @@
                     }
                     break;
                 }
+                case 27: {
+                    RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
+                    try {
+                        RRMCellQueue.get(rrmConfigStatus.getEcgi())
+                                .put("RRM Config's status: " + rrmConfigStatus.getStatus());
+                    } catch (InterruptedException e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        e.printStackTrace();
+                    } finally {
+                        RRMCellQueue.remove(rrmConfigStatus.getEcgi());
+                    }
+                    break;
+                }
                 case 34: {
                     TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
 
@@ -741,9 +824,11 @@
                             log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
                         }
                     });
+                    break;
                 }
                 default: {
                     log.warn("Wrong API ID");
+                    break;
                 }
             }