Completes CRD for sdxl2cp.

Changes:
- Implements monitoring service;
- Implements sdxl2cp command;
- Implements sdxl2cps-list command;
- Updates unit tests

Change-Id: I55b5f4e9cac9cd7270f5c56c0e9e902781206fd2
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
index 4bee790..02ea103 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
@@ -43,6 +43,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
+
 /**
  * SDX-L2 Store implementation backed by different distributed primitives.
  */
@@ -75,12 +76,15 @@
     private static String errorAddSdxL2CPSdx = "It is not possible to add %s " +
             "because the relative sdxl2 does not exist";
 
-    private static String errorGetSdxL2CPs = "It is not possible to list the sdxl2cps" +
+    private static String errorGetSdxL2CPs = "It is not possible to list the sdxl2cps " +
             "because sdxl2 %s does not exist";
 
     private static String errorRemoveSdxL2CP = "It is not possible to remove %s " +
             "because it does not exist";
 
+    private static String errorGetSdxL2CP = "It is not possible to retrieve %s " +
+            "because it does not exist";
+
     public void initForTest() {
 
         this.sdxL2s = Sets.newHashSet();
@@ -291,4 +295,23 @@
 
     }
 
+    /**
+     * Returns an SDX-L2 connection point in a SDX-L2.
+     *
+     * @param sdxl2cp the connection point name
+     * @return the relative SDXL2ConnectionPoint object
+     * @throws SdxL2Exception if SDX-L2 connection point does not exist
+     */
+    @Override
+    public SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception {
+        SdxL2ConnectionPoint sdxl2cpTemp = ImmutableSet.copyOf(sdxL2CPs.keySet()).parallelStream()
+                .filter(sdxl2cp_temp -> sdxl2cp_temp.name().equals(sdxl2cp)).findFirst().orElse(null);
+
+        if (sdxl2cpTemp == null) {
+            throw new SdxL2Exception(String.format(errorGetSdxL2CP, sdxl2cp));
+        }
+
+        return sdxl2cpTemp;
+    }
+
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
index f73fb24..d59b909 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
@@ -25,6 +25,10 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.edge.EdgePortService;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,16 +56,26 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentService intentService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EdgePortService edgePortService;
+
     protected ApplicationId appId;
 
+    protected SdxL2MonitoringService monitoringManager;
+
     @Activate
     protected void activate(ComponentContext context) {
         appId = coreService.registerApplication(SDXL2_APP);
+        monitoringManager = new SdxL2MonitoringManager(appId, intentService, edgePortService);
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
+        this.cleanSdxL2();
         log.info("Stopped");
     }
 
@@ -172,4 +186,54 @@
 
     }
 
+    /**
+     * Returns an SDX-L2 connection point in a SDX-L2.
+     *
+     * @param sdxl2cp SDX-L2 connection point name
+     * @return the relative SdxL2ConnectionPoint object
+     */
+    @Override
+    public SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) {
+        checkNotNull(sdxl2cp, "SdxL2ConnectionPoint name cannot be null");
+        try {
+            return this.sdxL2Store.getSdxL2ConnectionPoint(sdxl2cp);
+        } catch (SdxL2Exception e) {
+            log.info(e.getMessage());
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the state of the Intent that has been provided as input.
+     *
+     * @param intentKey key of the intent;
+     * @return the last state of the intent;
+     */
+    @Override
+    public SdxL2State getIntentState(Key intentKey) {
+        checkNotNull(intentKey, "Intent key cannot be null");
+        return this.monitoringManager.getIntentState(intentKey);
+    }
+
+    /**
+     * Returns the state of the EdgePort that has been provided as input.
+     *
+     * @param edgeport the connect point representing the edge port
+     * @return the last state of the edgeport;
+     */
+    @Override
+    public SdxL2State getEdgePortState(ConnectPoint edgeport) {
+        checkNotNull(edgeport, "Edge port cannot be null");
+        return this.monitoringManager.getEdgePortState(edgeport);
+    }
+
+    /**
+     * Cleans the state of the Application.
+     */
+    @Override
+    public void cleanSdxL2() {
+        this.monitoringManager.cleanup();
+    }
+
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringManager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringManager.java
new file mode 100644
index 0000000..734cbdc
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringManager.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.edge.EdgePortEvent;
+import org.onosproject.net.edge.EdgePortListener;
+import org.onosproject.net.edge.EdgePortService;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Implementation of the SdxL2MonitoringService.
+ */
+public class SdxL2MonitoringManager implements SdxL2MonitoringService {
+
+    private static Logger log = LoggerFactory.getLogger(SdxL2MonitoringManager.class);
+    protected ApplicationId appId;
+    private final IntentService intentService;
+    private final EdgePortService edgePortService;
+
+    /**
+     * It is a local cache for the Intents' events.
+     */
+    private ConcurrentMap<Key, IntentEvent> intentsState;
+    /**
+     * Last time intentsState has been updated.
+     */
+    private long lastIntentUpdate;
+
+    /**
+     * It is a local cache for the edge ports related events.
+     */
+    private ConcurrentMap<ConnectPoint, EdgePortEvent> edgeportsState;
+    /**
+     * Last time edgeportsState has been updated.
+     */
+    private long lastEdgePortUpdate;
+
+    // A kind of timeout which causes a manual update.
+    private static int deltaUpdate = 60000;
+
+    private InternalIntentListener intentListener;
+    private InternalEdgePortListener edgePortListener;
+
+    /**
+     * Creates an SdxL2MonitoringManager.
+     *
+     * @param sdxl2id application id.
+     * @param intentService reference to the Intent service.
+     * @param edgePortService reference to the EdgePort service.
+     */
+    public SdxL2MonitoringManager(ApplicationId sdxl2id, IntentService intentService, EdgePortService edgePortService) {
+
+        this.appId = sdxl2id;
+        this.intentListener = new InternalIntentListener();
+        this.edgePortListener = new InternalEdgePortListener();
+        this.intentService = intentService;
+        this.edgePortService = edgePortService;
+
+        this.intentService.addListener(this.intentListener);
+        this.edgePortService.addListener(this.edgePortListener);
+
+        this.intentsState = new ConcurrentHashMap<>();
+        this.edgeportsState = new ConcurrentHashMap<>();
+
+        this.lastEdgePortUpdate = 0;
+        this.lastIntentUpdate = 0;
+
+        log.info("Started");
+
+    }
+
+    /**
+     * Remove listeners.
+     */
+    public void cleanup() {
+        this.intentService.removeListener(intentListener);
+        this.edgePortService.removeListener(edgePortListener);
+    }
+
+    /**
+     * Returns the state of the Intent that has been provided as input.
+     *
+     * @param intentKey key of the intent;
+     * @return the last state of the intent;
+     */
+    @Override
+    public SdxL2State getIntentState(Key intentKey) {
+        synchronized (intentsState) {
+            IntentEvent event = this.intentsState.get(intentKey);
+            long ts = System.currentTimeMillis();
+            if (event == null || (ts > lastIntentUpdate && ts - lastIntentUpdate > deltaUpdate)) {
+                Intent intent = this.intentService.getIntent(intentKey);
+                IntentState intentState = this.intentService.getIntentState(intentKey);
+                event = IntentEvent.getEvent(intentState, intent).get();
+                intentsState.put(intentKey, event);
+                this.lastIntentUpdate = ts;
+            }
+            return this.getSdxL2State(event.type());
+        }
+    }
+
+    /**
+     * Updates intentsState after an Intent event.
+     *
+     * @param event the event just happened
+     */
+    private void processIntentEvent(IntentEvent event) {
+        synchronized (intentsState) {
+            intentsState.put(event.subject().key(), event);
+            this.lastIntentUpdate = System.currentTimeMillis();
+        }
+    }
+
+    /**
+     * Translates the type of the IntentEvent in SdxL2State.
+     *
+     * @param type the type of event
+     * @return the SdxL2State
+     */
+    private SdxL2State getSdxL2State(IntentEvent.Type type) {
+        SdxL2State state;
+        switch (type) {
+            case INSTALLED:
+                state = SdxL2State.ONLINE;
+                break;
+            case FAILED:
+                state = SdxL2State.OFFLINE;
+                break;
+            case INSTALL_REQ:
+            case WITHDRAW_REQ:
+            case WITHDRAWN:
+            case CORRUPT:
+            case PURGED:
+            default:
+                state = SdxL2State.CHECK;
+        }
+        return state;
+    }
+
+    private class InternalIntentListener implements IntentListener {
+
+        /**
+         * Reacts to the specified event.
+         *
+         * @param event event to be processed
+         */
+        @Override
+        public void event(IntentEvent event) {
+            Intent intent = event.subject();
+            if (intent.appId().equals(appId)) {
+                if (event.type() == IntentEvent.Type.INSTALLED ||
+                        event.type() == IntentEvent.Type.FAILED ||
+                        event.type() == IntentEvent.Type.WITHDRAWN) {
+                    log.info("Intent {} {}", event.subject().key(), event.type());
+                }
+                processIntentEvent(event);
+            }
+        }
+
+    }
+
+    /**
+     * Returns the state of the EdgePort that has been provided as input.
+     *
+     * @param edgeport the connect point representing the edge port
+     * @return the last state of the edge port;
+     */
+    @Override
+    public SdxL2State getEdgePortState(ConnectPoint edgeport) {
+        synchronized (edgeportsState) {
+            EdgePortEvent event = this.edgeportsState.get(edgeport);
+            long ts = System.currentTimeMillis();
+            if (event == null ||
+                    (ts > lastEdgePortUpdate && ts - lastEdgePortUpdate > deltaUpdate)) {
+                event = new EdgePortEvent(EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeport);
+                Iterator<ConnectPoint> cps = this.edgePortService.getEdgePoints(edgeport.deviceId()).iterator();
+                while (cps.hasNext()) {
+                    if (edgeport.equals(cps.next())) {
+                        event = new EdgePortEvent(EdgePortEvent.Type.EDGE_PORT_ADDED, edgeport);
+                        break;
+                    }
+                }
+                edgeportsState.put(edgeport, event);
+                this.lastEdgePortUpdate = ts;
+            }
+            return this.getSdxL2State(event.type());
+        }
+    }
+
+    /**
+     * Updates edgeportsState after an EdgePort event.
+     *
+     * @param event the event just happened
+     */
+    private void processEdgePortEvent(EdgePortEvent event) {
+        synchronized (edgeportsState) {
+            edgeportsState.put(event.subject(), event);
+            this.lastEdgePortUpdate = System.currentTimeMillis();
+        }
+    }
+
+    /**
+     * Translates the type of EdgePortEvent in SdxL2State.
+     *
+     * @param type the type of event
+     * @return the SdxL2State
+     */
+    private SdxL2State getSdxL2State(EdgePortEvent.Type type) {
+        return type == EdgePortEvent.Type.EDGE_PORT_ADDED ? SdxL2State.ONLINE : SdxL2State.OFFLINE;
+    }
+
+    private class InternalEdgePortListener implements EdgePortListener {
+
+        /**
+         * Reacts to the specified event.
+         *
+         * @param event event to be processed
+         */
+        @Override
+        public void event(EdgePortEvent event) {
+            ConnectPoint cp = event.subject();
+            log.info("ConnectPoint {}/{} {}", cp.elementId().toString(), cp.port().toString(), event.type().toString());
+            processEdgePortEvent(event);
+
+        }
+
+    }
+
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringService.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringService.java
new file mode 100644
index 0000000..4da17e0
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MonitoringService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.intent.Key;
+
+/**
+ * Service that provides the current state of
+ * the SDX-L2 related intents and of the
+ * client interfaces.
+ */
+public interface SdxL2MonitoringService {
+
+    /**
+     * Returns the state of the Intent that has been provided as input.
+     *
+     * @param intentKey key of the intent;
+     * @return the last state of the intent;
+     */
+    SdxL2State getIntentState(Key intentKey);
+
+    /**
+     * Returns the state of the EdgePort that has been provided as input.
+     *
+     * @param edgeport the connect point representing the edge port
+     * @return the last state of the edge port;
+     */
+    SdxL2State getEdgePortState(ConnectPoint edgeport);
+
+    /**
+     * Remove listeners.
+     */
+    void cleanup();
+
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
index 57c1be2..94629d7 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
@@ -16,6 +16,9 @@
 
 package org.onosproject.sdxl2;
 
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.intent.Key;
+
 import java.util.Optional;
 import java.util.Set;
 
@@ -70,4 +73,33 @@
      */
     void removeSdxL2ConnectionPoint(String sdxl2cp);
 
+    /**
+     * Returns an SDX-L2 connection point in a SDX-L2.
+     *
+     * @param sdxl2cp SDX-L2 connection point name
+     * @return the relative SdxL2ConnectionPoint object
+     */
+    SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp);
+
+    /**
+     * Returns the state of the Intent that has been provided as input.
+     *
+     * @param intentKey key of the intent;
+     * @return the last state of the intent;
+     */
+    SdxL2State getIntentState(Key intentKey);
+
+    /**
+     * Returns the state of the EdgePort that has been provided as input.
+     *
+     * @param edgeport the connect point representing the edge port
+     * @return the last state of the edgeport;
+     */
+    SdxL2State getEdgePortState(ConnectPoint edgeport);
+
+    /**
+     * Cleans the state of the Application.
+     */
+    void cleanSdxL2();
+
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2State.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2State.java
new file mode 100644
index 0000000..ae00561
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2State.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+/**
+ * Representation of the states the SDX-L2 resources may attain during the time.
+ */
+public enum SdxL2State {
+
+    /**
+     * Signifies that the resource is available.
+     */
+    ONLINE,
+
+    /**
+     * Signifies that the resource is not available (currently).
+     */
+    OFFLINE,
+
+    /**
+     * Signifies that the resource has some problems. Further
+     * investigation is needed.
+     *
+     */
+    CHECK
+
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
index 217a52a..c19ee42 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
@@ -75,4 +75,13 @@
      */
     void removeSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception;
 
+    /**
+     * Returns an SDX-L2 connection point in a SDX-L2.
+     *
+     * @param sdxl2cp the connection point name
+     * @return the relative SDXL2ConnectionPoint object
+     * @throws SdxL2Exception if SDX-L2 connection point does not exist
+     */
+    SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception;
+
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java
new file mode 100644
index 0000000..8f5b3ea
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl2.SdxL2ConnectionPoint;
+import org.onosproject.sdxl2.SdxL2Service;
+import org.onosproject.sdxl2.SdxL2State;
+
+/**
+ * Cli to print the details of an SdxL2ConnectionPoint.
+ */
+@Command(scope = "sdxl2", name = "sdxl2cp", description = "Prints the details of an SDXL2ConnectionPoint")
+public class SdxL2GetCPCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "sdxl2cpname", description = "Sdxl2cp name", required = true, multiValued = false)
+    String sdxl2cpname = null;
+
+    private static final String HEADER       = "\n\u001B[1;37mStatus\t\t" +
+            "Connection Point\t\tName\t\tVlan IDs\t\tCE Mac Address\u001B[0m";
+    private static final String SEPARATOR    = "\u001B[1;37m------------" +
+            "-----------------------------------------------------------" +
+            "--------------------------------------\u001B[0m";
+    private static final String FORMAT_SDXL2CP_ONLINE   = "\u001B[1;32m%" +
+            "s\u001B[0m\t\t\u001B[1;37m%s/%s\t\t%s\t\t%s\t\t%s\u001B[0m\n";
+    private static final String FORMAT_SDXL2CP_OFFLINE  = "\u001B[1;31m%" +
+            "s\u001B[0m\t\t\u001B[1;37m%s/%s\t\t%s\t\t%s\t\t%s\u001B[0m\n";
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        SdxL2ConnectionPoint sdxl2ConnectionPoint = sdxl2Service.getSdxL2ConnectionPoint(sdxl2cpname);
+        if (sdxl2ConnectionPoint == null) {
+            return;
+        }
+        SdxL2State sdxl2cpState = sdxl2Service.getEdgePortState(sdxl2ConnectionPoint.connectPoint());
+        print(HEADER);
+        print(SEPARATOR);
+        if (sdxl2cpState == SdxL2State.ONLINE) {
+            print(FORMAT_SDXL2CP_ONLINE,
+                    "ONLINE",
+                    sdxl2ConnectionPoint.connectPoint().elementId(),
+                    sdxl2ConnectionPoint.connectPoint().port(),
+                    sdxl2ConnectionPoint.name(),
+                    sdxl2ConnectionPoint.vlanIds(),
+                    sdxl2ConnectionPoint.macAddress());
+        } else if (sdxl2cpState == SdxL2State.OFFLINE) {
+            print(FORMAT_SDXL2CP_OFFLINE,
+                    "OFFLINE",
+                    sdxl2ConnectionPoint.connectPoint().elementId(),
+                    sdxl2ConnectionPoint.connectPoint().port(),
+                    sdxl2ConnectionPoint.name(),
+                    sdxl2ConnectionPoint.vlanIds(),
+                    sdxl2ConnectionPoint.macAddress());
+        }
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java
new file mode 100644
index 0000000..b25f349
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl2.SdxL2ConnectionPoint;
+import org.onosproject.sdxl2.SdxL2Service;
+import org.onosproject.sdxl2.SdxL2State;
+
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * CLI to list the SDX-L2 connection points.
+ */
+@Command(scope = "sdxl2", name = "sdxl2cps-list", description = "Lists " +
+        "all the sdxl2 connection points. Argument not required the name of sdxl2")
+public class SdxL2ListCPCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "sdxl2name", description = "sdxl2name", required = false, multiValued = false)
+    String sdxl2 = null;
+
+    private static final String HEADER = "\n\u001B[1;37mStatus\t\tSDXL2 Connection Point\u001B[0m";
+    private static final String SEPARATOR = "\u001B[1;37m-----------------------------------------------\u001B[0m";
+    private static final String FORMAT_SDXL2CP_ONLINE = "\u001B[1;32m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+    private static final String FORMAT_SDXL2CP_OFFLINE = "\u001B[1;31m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        Optional<String> sdxl2name = Optional.ofNullable(sdxl2);
+        Set<String> result = sdxl2Service.getSdxL2ConnectionPoints(sdxl2name);
+        SdxL2ConnectionPoint sdxl2ConnectionPoint;
+        SdxL2State sdxl2cpState;
+        if (result.size() > 0) {
+            print(HEADER);
+            print(SEPARATOR);
+            for (String sdxl2cp : result) {
+                sdxl2ConnectionPoint = sdxl2Service.getSdxL2ConnectionPoint(sdxl2cp);
+                if (sdxl2ConnectionPoint == null) {
+                    return;
+                }
+                sdxl2cpState = sdxl2Service.getEdgePortState(sdxl2ConnectionPoint.connectPoint());
+                if (sdxl2cpState == SdxL2State.ONLINE) {
+                    print(FORMAT_SDXL2CP_ONLINE, "ONLINE", sdxl2cp);
+                } else if (sdxl2cpState == SdxL2State.OFFLINE) {
+                    print(FORMAT_SDXL2CP_OFFLINE, "OFFLINE", sdxl2cp);
+                }
+            }
+            print("");
+        }
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
index 56fc850..42f91d1 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
@@ -28,9 +28,9 @@
 @Command(scope = "sdxl2", name = "sdxl2-list", description = "Lists the sdx-l2s")
 public class SdxL2ListCommand extends AbstractShellCommand {
 
-    private static final String HEADER           = "\n\u001B[1;37mSDXL2\u001B[0m";
-    private static final String SEPARATOR        = "\u001B[1;37m--------------\u001B[0m";
-    private static final String FORMAT_SDXL2     = "\u001B[1;37m%s\u001B[0m";
+    private static final String HEADER = "\n\u001B[1;37mSDXL2\u001B[0m";
+    private static final String SEPARATOR = "\u001B[1;37m--------------\u001B[0m";
+    private static final String FORMAT_SDXL2 = "\u001B[1;37m%s\u001B[0m";
 
     @Override
     protected void execute() {