Implemented node backend connection

This commit is contained in:
Andrey Terentev 2023-11-26 21:00:45 +07:00
parent c05d5853eb
commit 8cd58228dd
10 changed files with 158 additions and 14 deletions

View File

@ -13,15 +13,18 @@ import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import lombok.Setter;
import ru.dragonestia.loadbalancer.web.model.Node; import ru.dragonestia.loadbalancer.web.model.Node;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
public class NodeList extends VerticalLayout { public class NodeList extends VerticalLayout {
private final Grid<Node> nodesGrid; private final Grid<Node> nodesGrid;
private final TextField searchField; private final TextField searchField;
private List<Node> cachedNodes; private List<Node> cachedNodes;
@Setter private Consumer<String> removeMethod;
public NodeList(List<Node> nodes) { public NodeList(List<Node> nodes) {
super(); super();
@ -125,6 +128,8 @@ public class NodeList extends VerticalLayout {
} }
private void removeNode(Node node) { private void removeNode(Node node) {
// TODO: send remove request and getting nodes list if (removeMethod != null) {
removeMethod.accept(node.identifier());
}
} }
} }

View File

@ -3,7 +3,9 @@ package ru.dragonestia.loadbalancer.web.model;
import lombok.NonNull; import lombok.NonNull;
import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod; import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod;
public record Node(@NonNull String identifier, @NonNull LoadBalancingMethod method) { import java.io.Serializable;
public record Node(@NonNull String identifier, @NonNull LoadBalancingMethod method) implements Serializable {
@Override @Override
public int hashCode() { public int hashCode() {

View File

@ -7,6 +7,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import ru.dragonestia.loadbalancer.web.component.AddUsers;
import ru.dragonestia.loadbalancer.web.component.NavPath; import ru.dragonestia.loadbalancer.web.component.NavPath;
import ru.dragonestia.loadbalancer.web.model.Bucket; import ru.dragonestia.loadbalancer.web.model.Bucket;
import ru.dragonestia.loadbalancer.web.model.Node; import ru.dragonestia.loadbalancer.web.model.Node;
@ -17,6 +18,7 @@ import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
public class BucketsPage extends VerticalLayout implements BeforeEnterObserver { public class BucketsPage extends VerticalLayout implements BeforeEnterObserver {
private Bucket bucket; private Bucket bucket;
private AddUsers addUsers;
@Override @Override
public void beforeEnter(BeforeEnterEvent event) { public void beforeEnter(BeforeEnterEvent event) {
@ -40,7 +42,7 @@ public class BucketsPage extends VerticalLayout implements BeforeEnterObserver {
add(new H2("Bucket details")); add(new H2("Bucket details"));
printBucketDetails(); printBucketDetails();
add(new Hr()); add(new Hr());
add(new H2("Add users")); add(addUsers = new AddUsers(bucket));
add(new Hr()); add(new Hr());
add(new H2("Users")); add(new H2("Users"));
} }

View File

@ -3,12 +3,16 @@ package ru.dragonestia.loadbalancer.web.page;
import com.vaadin.flow.component.Html; import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Hr; import com.vaadin.flow.component.html.Hr;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import lombok.Getter; import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import ru.dragonestia.loadbalancer.web.component.BucketList; import ru.dragonestia.loadbalancer.web.component.BucketList;
import ru.dragonestia.loadbalancer.web.component.NavPath; import ru.dragonestia.loadbalancer.web.component.NavPath;
import ru.dragonestia.loadbalancer.web.component.RegisterBucket; import ru.dragonestia.loadbalancer.web.component.RegisterBucket;
@ -16,6 +20,7 @@ import ru.dragonestia.loadbalancer.web.model.Bucket;
import ru.dragonestia.loadbalancer.web.model.Node; import ru.dragonestia.loadbalancer.web.model.Node;
import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod; import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod;
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit; import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
import ru.dragonestia.loadbalancer.web.repository.NodeRepository;
import java.util.List; import java.util.List;
@ -24,10 +29,15 @@ import java.util.List;
@Route("/nodes/:nodeId") @Route("/nodes/:nodeId")
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver { public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {
private final NodeRepository nodeRepository;
private Node node; private Node node;
private RegisterBucket registerBucket; private RegisterBucket registerBucket;
private BucketList bucketList; private BucketList bucketList;
public NodeDetailsPage(@Autowired NodeRepository nodeRepository) {
this.nodeRepository = nodeRepository;
}
@Override @Override
public void beforeEnter(BeforeEnterEvent event) { public void beforeEnter(BeforeEnterEvent event) {
var nodeIdOpt = event.getRouteParameters().get("nodeId"); var nodeIdOpt = event.getRouteParameters().get("nodeId");
@ -35,7 +45,19 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
getUI().ifPresent(ui -> ui.navigate("/nodes")); getUI().ifPresent(ui -> ui.navigate("/nodes"));
return; return;
} }
node = new Node(nodeIdOpt.get(), LoadBalancingMethod.ROUND_ROBIN); // TODO: getting node var nodeId = nodeIdOpt.get();
add(new NavPath(new NavPath.Point("Nodes", "/nodes"), new NavPath.Point(nodeId, "/nodes/" + nodeId)));
var nodeOpt = nodeRepository.findNode(nodeId);
if (nodeOpt.isEmpty()) {
add(new H2("Error 404"));
add(new Paragraph("Node not found"));
Notification.show("Node '" + nodeId + "' does not exist", 3000, Notification.Position.TOP_END)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
node = nodeOpt.get(); // TODO: getting node
// TODO: getting buckets // TODO: getting buckets
initComponents(node, List.of( initComponents(node, List.of(
@ -47,9 +69,6 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
} }
private void initComponents(Node node, List<Bucket> buckets) { private void initComponents(Node node, List<Bucket> buckets) {
add(new NavPath(new NavPath.Point("Nodes", "/nodes"),
new NavPath.Point(node.identifier(), "/nodes/" + node.identifier())));
printNodeDetails(node); printNodeDetails(node);
add(new Hr()); add(new Hr());
add(registerBucket = new RegisterBucket(node, (bucket) -> { add(registerBucket = new RegisterBucket(node, (bucket) -> {

View File

@ -5,38 +5,55 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import lombok.Getter; import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import ru.dragonestia.loadbalancer.web.component.NavPath; import ru.dragonestia.loadbalancer.web.component.NavPath;
import ru.dragonestia.loadbalancer.web.component.NodeList; import ru.dragonestia.loadbalancer.web.component.NodeList;
import ru.dragonestia.loadbalancer.web.component.RegisterNode; import ru.dragonestia.loadbalancer.web.component.RegisterNode;
import ru.dragonestia.loadbalancer.web.repository.NodeRepository;
import java.util.List; @Log4j2
@Getter @Getter
@PageTitle("Nodes") @PageTitle("Nodes")
@Route("/nodes") @Route("/nodes")
public class NodesPage extends VerticalLayout { public class NodesPage extends VerticalLayout {
private final NodeRepository nodeRepository;
private final RegisterNode registerNode; private final RegisterNode registerNode;
private final NodeList nodeList; private final NodeList nodeList;
public NodesPage() { public NodesPage(@Autowired NodeRepository nodeRepository) {
super(); super();
this.nodeRepository = nodeRepository;
add(new NavPath(new NavPath.Point("Nodes", "/nodes"))); add(new NavPath(new NavPath.Point("Nodes", "/nodes")));
add(registerNode = createRegisterNodeElement()); add(registerNode = createRegisterNodeElement());
add(new Hr()); add(new Hr());
add(nodeList = createNodeListElement()); add(nodeList = createNodeListElement());
nodeList.setRemoveMethod(nodeIdentifier -> {
nodeRepository.removeNode(nodeIdentifier);
nodeList.update(nodeRepository.getNodes());
});
} }
protected RegisterNode createRegisterNodeElement() { protected RegisterNode createRegisterNodeElement() {
return new RegisterNode(node -> { return new RegisterNode(node -> {
nodeList.update(List.of(node)); // remove it later try {
return new RegisterNode.Response(false, "Some error"); // TODO nodeRepository.registerNode(node);
return new RegisterNode.Response(false, "");
} catch (Error ex) {
return new RegisterNode.Response(true, ex.getMessage());
} catch (RuntimeException ex) {
log.throwing(ex);
return new RegisterNode.Response(true, ex.getMessage());
} finally {
nodeList.update(nodeRepository.getNodes());
}
}); });
} }
protected NodeList createNodeListElement() { protected NodeList createNodeListElement() {
// TODO: getting nodes list return new NodeList(nodeRepository.getNodes());
return new NodeList(List.of());
} }
} }

View File

@ -0,0 +1,17 @@
package ru.dragonestia.loadbalancer.web.repository;
import ru.dragonestia.loadbalancer.web.model.Node;
import java.util.List;
import java.util.Optional;
public interface NodeRepository {
void registerNode(Node node);
List<Node> getNodes();
Optional<Node> findNode(String identifier);
void removeNode(String identifier);
}

View File

@ -0,0 +1,67 @@
package ru.dragonestia.loadbalancer.web.repository.impl;
import com.vaadin.flow.spring.annotation.SpringComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import ru.dragonestia.loadbalancer.web.model.Node;
import ru.dragonestia.loadbalancer.web.repository.NodeRepository;
import ru.dragonestia.loadbalancer.web.repository.impl.response.NodeDetailsResponse;
import ru.dragonestia.loadbalancer.web.repository.impl.response.NodeListResponse;
import ru.dragonestia.loadbalancer.web.repository.impl.response.NodeRegisterResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
@Log4j2
@RequiredArgsConstructor
@SpringComponent
public class NodeRepositoryImpl implements NodeRepository {
private final RestUtil rest;
@Override
public void registerNode(Node node) {
NodeRegisterResponse response;
try {
response = rest.post(URI.create("nodes"),
NodeRegisterResponse.class,
params -> {
params.put("identifier", node.identifier());
params.put("method", node.method().name());
});
} catch (Exception ex) {
throw new RuntimeException("Internal error", ex);
}
if (!response.success()) {
throw new Error(response.message());
}
}
@Override
public List<Node> getNodes() {
return rest.get(URI.create("nodes"), NodeListResponse.class).nodes();
}
@Override
public Optional<Node> findNode(String identifier) {
try {
var response = rest.get(URI.create("nodes/" + identifier), NodeDetailsResponse.class);
return Optional.of(response.node());
} catch (Exception ex) {
return Optional.empty();
}
}
@Override
public void removeNode(String identifier) {
rest.delete(URI.create("nodes/" + identifier), params -> {});
}
}

View File

@ -0,0 +1,5 @@
package ru.dragonestia.loadbalancer.web.repository.impl.response;
import ru.dragonestia.loadbalancer.web.model.Node;
public record NodeDetailsResponse(Node node) {}

View File

@ -0,0 +1,7 @@
package ru.dragonestia.loadbalancer.web.repository.impl.response;
import ru.dragonestia.loadbalancer.web.model.Node;
import java.util.List;
public record NodeListResponse(List<Node> nodes) {}

View File

@ -0,0 +1,3 @@
package ru.dragonestia.loadbalancer.web.repository.impl.response;
public record NodeRegisterResponse(boolean success, String message) {}