/*
 * Copyright 2014-2015 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.cli;

import static com.google.common.collect.Lists.newArrayList;

import java.util.Collections;
import java.util.List;

import org.apache.karaf.shell.commands.Command;
import org.onlab.util.Tools;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ControllerNode;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;

/**
 * Lists all controller cluster nodes.
 */
@Command(scope = "onos", name = "nodes",
         description = "Lists all controller cluster nodes")
public class NodesListCommand extends AbstractShellCommand {

    private static final String FMT =
            "id=%s, address=%s:%s, state=%s, updated=%s %s";

    @Override
    protected void execute() {
        ClusterService service = get(ClusterService.class);
        List<ControllerNode> nodes = newArrayList(service.getNodes());
        Collections.sort(nodes, Comparators.NODE_COMPARATOR);
        if (outputJson()) {
            print("%s", json(service, nodes));
        } else {
            ControllerNode self = service.getLocalNode();
            for (ControllerNode node : nodes) {
                print(FMT, node.id(), node.ip(), node.tcpPort(),
                      service.getState(node.id()),
                      Tools.timeAgo(service.getLastUpdated(node.id()).getMillis()),
                      node.equals(self) ? "*" : "");
            }
        }
    }

    // Produces JSON structure.
    private JsonNode json(ClusterService service, List<ControllerNode> nodes) {
        ObjectMapper mapper = new ObjectMapper();
        ArrayNode result = mapper.createArrayNode();
        ControllerNode self = service.getLocalNode();
        for (ControllerNode node : nodes) {
            result.add(mapper.createObjectNode()
                               .put("id", node.id().toString())
                               .put("ip", node.ip().toString())
                               .put("tcpPort", node.tcpPort())
                               .put("state", service.getState(node.id()).toString())
                               .put("self", node.equals(self)));
        }
        return result;
    }

}

@@ -649,116 +649,210 @@
 ort 
-static com.google.common.collect.Lists.newArrayList;%0A%0Aimport java.util.Collections;%0Aimport java.util.List
+com.fasterxml.jackson.databind.JsonNode;%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0Aimport com.fasterxml.jackson.databind.node.ArrayNode;%0Aimport com.fasterxml.jackson.databind.node.ObjectNode
 ;%0A
-%0A
 impo
@@ -895,16 +895,47 @@
 ommand;%0A
+import org.joda.time.DateTime;%0A
 import o
@@ -1061,156 +1061,117 @@
 ort 
-com.fasterxml.jackson.databind.JsonNode;%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0Aimport com.fasterxml.jackson.databind.node.
+java.util.Collections;%0Aimport java.util.List;%0A%0Aimport static com.google.common.collect.Lists.new
 Array
-Node
+List
 ;%0A%0A
+%0A
 /**%0A
@@ -1905,32 +1905,279 @@
 node : nodes) %7B%0A
+                DateTime lastUpdated = service.getLastUpdated(node.id());%0A                String timeAgo = %22Never%22;%0A                if (lastUpdated != null) %7B%0A                    timeAgo = Tools.timeAgo(lastUpdated.getMillis());%0A                %7D%0A
                 
@@ -2302,68 +2302,15 @@
     
-Tools.
 timeAgo
-(service.getLastUpdated(node.id()).getMillis())
 ,%0A  
@@ -2720,19 +2720,103 @@
     
-result.add(
+ControllerNode.State nodeState = service.getState(node.id());%0A            ObjectNode newNode = 
 mapp
@@ -3070,70 +3070,72 @@
 t(%22s
-tate%22, service.getState(node.id()).toString())%0A               
+elf%22, node.equals(self));%0A%0A            if (nodeState != null) %7B%0A
     
@@ -3150,39 +3150,96 @@
     
+newNode
 .put(%22s
-elf
+tate
 %22, node
-.equals(self))
+State.toString());%0A            %7D%0A            result.add(newNode
 );%0A 

Fix for ONOS-1715: NPE in nodes cli command