org.opendaylight.jsonrpc.dom.codec.JsonRpcPathBuilder Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2020 Lumina Networks, Inc. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.jsonrpc.dom.codec;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
/**
* Fluent builder of JSONRPC path.
*
* @author Richard Kosegi
*/
@Beta
public class JsonRpcPathBuilder {
private static class PathArgument {
private final Optional name;
private final List> keys = new ArrayList<>(2);
PathArgument(String name) {
this.name = Optional.of(name);
this.keys.addAll(Collections.emptyList());
}
PathArgument(Collection> keys) {
this.name = Optional.empty();
this.keys.addAll(keys);
}
static PathArgument of(String item) {
return new PathArgument(item);
}
static PathArgument of(Collection> keys) {
return new PathArgument(keys);
}
boolean isKeyed() {
return !keys.isEmpty();
}
}
private final Deque path = new LinkedList<>();
protected JsonRpcPathBuilder() {
// NOOP
}
public static JsonRpcPathBuilder newBuilder(String container) {
return new JsonRpcPathBuilder().container(container);
}
public static JsonRpcPathBuilder newBuilder() {
return new JsonRpcPathBuilder();
}
public JsonObject build() {
JsonElement parent = new JsonObject();
final JsonObject root = parent.getAsJsonObject();
// make a copy to allow re-use of same builder instance
final Deque copy = new LinkedList<>(path);
for (;;) {
final PathArgument current = copy.poll();
if (current == null) {
break;
}
if (current.isKeyed()) {
final JsonObject next = new JsonObject();
for (Entry entry : current.keys) {
next.addProperty(entry.getKey(), entry.getValue());
}
parent.getAsJsonArray().add(next);
parent = next;
} else {
final JsonElement next = isNextKeyed(copy) ? new JsonArray() : new JsonObject();
parent.getAsJsonObject().add(current.name.orElseThrow(), next);
parent = next;
}
}
return root;
}
private static boolean isNextKeyed(Deque stack) {
final PathArgument element = stack.peek();
return element != null && element.isKeyed();
}
/**
* Append container (or list) to path arguments.
*
* @param container name of element to append
* @return this builder instance
*/
public JsonRpcPathBuilder container(@NonNull String container) {
path.add(PathArgument.of(container));
return this;
}
/**
* Append individual list item into path arguments.
*
* @param key list item key name
* @param value list item key value
* @return this builder instance
*/
public JsonRpcPathBuilder item(@NonNull String key, @NonNull String value) {
item(Collections.singletonList(new AbstractMap.SimpleEntry<>(key, value)));
return this;
}
/**
* Append individual list item into path arguments.
*
* @param key1 list item key1 name
* @param value1 list item key1 value
* @param key2 list item key2 name
* @param value2 list item key2 value
* @return this builder instance
*/
public JsonRpcPathBuilder item(@NonNull String key1, @NonNull String value1, @NonNull String key2,
@NonNull String value2) {
item(ImmutableList.of(new AbstractMap.SimpleEntry<>(key1, value1),
new AbstractMap.SimpleEntry<>(key2, value2)));
return this;
}
/**
* Append individual list item into path arguments.
*
* @param keys {@link Collection} of item keys (name/value pairs)
* @return this builder instance
*/
public JsonRpcPathBuilder item(@NonNull Collection> keys) {
Objects.requireNonNull(keys);
path.add(PathArgument.of(keys));
return this;
}
}