Ray Milkey
Committed by Gerrit Code Review

ONOS-3379: Config REST 500 errors on GET operations if keys don't exist

Change-Id: Ie32bdb70693c5571421840265b4be71d0706d797
......@@ -40,6 +40,7 @@ import java.util.Collection;
import java.util.Dictionary;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
......@@ -144,6 +145,23 @@ public abstract class Tools {
}
/**
* Returns the specified set if the set is not null and not empty;
* otherwise throws a not found exception.
*
* @param item set to check
* @param message not found message
* @param <T> Set item type
* @return item if not null and not empty
* @throws org.onlab.util.ItemNotFoundException if set is null or empty
*/
public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) {
if (item == null || item.isEmpty()) {
throw new ItemNotFoundException(message);
}
return item;
}
/**
* Returns the specified item if that item is not null; otherwise throws
* bad argument exception.
*
......
......@@ -15,10 +15,9 @@
*/
package org.onosproject.rest.resources;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.SubjectFactory;
import org.onosproject.rest.AbstractWebResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
......@@ -29,8 +28,16 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.SubjectFactory;
import org.onosproject.rest.AbstractWebResource;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static org.onlab.util.Tools.emptyIsNotFound;
import static org.onlab.util.Tools.nullIsNotFound;
/**
* Manage network configurations.
......@@ -38,8 +45,29 @@ import java.io.InputStream;
@Path("network/configuration")
public class NetworkConfigWebResource extends AbstractWebResource {
private String subjectClassNotFoundErrorString(String subjectClassKey) {
return "Config for '" + subjectClassKey + "' not found";
}
private String subjectNotFoundErrorString(String subjectClassKey,
String subjectKey) {
return "Config for '"
+ subjectClassKey + "/" + subjectKey
+ "' not found";
}
private String configKeyNotFoundErrorString(String subjectClassKey,
String subjectKey,
String configKey) {
return "Config for '"
+ subjectClassKey + "/" + subjectKey + "/" + configKey
+ "' not found";
}
/**
* Get entire network configuration base.
*
* @rsModel NetCfgGet
* @return network configuration JSON
*/
......@@ -70,7 +98,9 @@ public class NetworkConfigWebResource extends AbstractWebResource {
public Response download(@PathParam("subjectClassKey") String subjectClassKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
SubjectFactory subjectFactory =
nullIsNotFound(service.getSubjectFactory(subjectClassKey),
subjectClassNotFoundErrorString(subjectClassKey));
produceJson(service, root, subjectFactory, subjectFactory.subjectClass());
return ok(root).build();
}
......@@ -90,8 +120,12 @@ public class NetworkConfigWebResource extends AbstractWebResource {
@PathParam("subjectKey") String subjectKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
produceSubjectJson(service, root, subjectFactory.createSubject(subjectKey));
SubjectFactory subjectFactory =
nullIsNotFound(service.getSubjectFactory(subjectClassKey),
subjectClassNotFoundErrorString(subjectClassKey));
produceSubjectJson(service, root, subjectFactory.createSubject(subjectKey),
true,
subjectNotFoundErrorString(subjectClassKey, subjectKey));
return ok(root).build();
}
......@@ -111,20 +145,40 @@ public class NetworkConfigWebResource extends AbstractWebResource {
@PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey) {
NetworkConfigService service = get(NetworkConfigService.class);
return ok(service.getConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
service.getConfigClass(subjectClassKey, configKey)).node()).build();
Object subject =
nullIsNotFound(service.getSubjectFactory(subjectClassKey)
.createSubject(subjectKey),
subjectNotFoundErrorString(subjectClassKey, subjectKey));
Class configClass =
nullIsNotFound(service.getConfigClass(subjectClassKey, configKey),
configKeyNotFoundErrorString(subjectClassKey, subjectKey, configKey));
Config config =
nullIsNotFound(service.getConfig(subject, configClass),
configKeyNotFoundErrorString(subjectClassKey,
subjectKey,
configKey));
return ok(config.node()).build();
}
@SuppressWarnings("unchecked")
private void produceJson(NetworkConfigService service, ObjectNode node,
SubjectFactory subjectFactory, Class subjectClass) {
service.getSubjects(subjectClass).forEach(s ->
produceSubjectJson(service, newObject(node, subjectFactory.subjectKey(s)), s));
produceSubjectJson(service, newObject(node, subjectFactory.subjectKey(s)), s, false, ""));
}
private void produceSubjectJson(NetworkConfigService service, ObjectNode node,
Object subject) {
service.getConfigs(subject).forEach(c -> node.set(c.key(), c.node()));
Object subject,
boolean emptyIsError,
String emptyErrorMessage) {
Set<? extends Config<Object>> configs = service.getConfigs(subject);
if (emptyIsError) {
// caller wants an empty set to be a 404
configs = emptyIsNotFound(configs, emptyErrorMessage);
}
configs.forEach(c -> node.set(c.key(), c.node()));
}
......