From 96299218ece3c7b15c32aa1f476875d78a5ad84a Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Thu, 30 Nov 2023 21:22:29 +0700 Subject: [PATCH] Implemented registration and getting buckets --- .../web/component/BucketList.java | 44 ++++++++++--------- .../loadbalancer/web/model/Bucket.java | 20 +++++++-- .../web/model/type/SlotLimit.java | 12 ++--- .../loadbalancer/web/page/BucketsPage.java | 2 +- .../web/page/NodeDetailsPage.java | 6 ++- .../web/repository/BucketRepository.java | 4 +- .../repository/impl/BucketRepositoryImpl.java | 10 ++++- .../impl/response/BucketListResponse.java | 4 +- .../controller/BucketController.java | 19 ++++++-- .../response/BucketListResponse.java | 7 ++- .../loadbalancer/model/type/SlotLimit.java | 3 ++ 11 files changed, 84 insertions(+), 47 deletions(-) diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/BucketList.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/BucketList.java index cbbbe2f..5b76af4 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/BucketList.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/BucketList.java @@ -15,19 +15,21 @@ import com.vaadin.flow.component.notification.NotificationVariant; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; +import lombok.Setter; import ru.dragonestia.loadbalancer.web.model.Bucket; -import ru.dragonestia.loadbalancer.web.repository.BucketRepository; import java.util.List; +import java.util.function.Consumer; public class BucketList extends VerticalLayout { private final String nodeIdentifier; - private final Grid bucketsGrid; + private final Grid bucketsGrid; private final TextField searchField; - private List cachedBuckets; + private List cachedBuckets; + @Setter private Consumer removeMethod; - public BucketList(String nodeIdentifier, List buckets) { + public BucketList(String nodeIdentifier, List buckets) { this.nodeIdentifier = nodeIdentifier; cachedBuckets = buckets; @@ -51,20 +53,20 @@ public class BucketList extends VerticalLayout { var temp = input.trim(); bucketsGrid.setItems(cachedBuckets.stream() - .filter(bucket -> bucket.identifier().startsWith(temp)) + .filter(bucket -> bucket.getIdentifier().startsWith(temp)) .toList()); } - private Grid createGrid() { - var grid = new Grid<>(BucketRepository.BucketInfo.class, false); - grid.addColumn(BucketRepository.BucketInfo::identifier).setHeader("Identifier"); + private Grid createGrid() { + var grid = new Grid<>(Bucket.class, false); + grid.addColumn(Bucket::getIdentifier).setHeader("Identifier"); grid.addComponentColumn(bucket -> { var result = new Span(); - if (bucket.slots() == -1) { + if (bucket.getSlots().isUnlimited()) { result.setText("Unlimited"); result.getElement().getThemeList().add("badge contrast"); } else { - result.setText(Integer.toString(bucket.slots())); + result.setText(Integer.toString(bucket.getSlots().slots())); } return result; }).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER); @@ -72,7 +74,7 @@ public class BucketList extends VerticalLayout { return grid; } - private HorizontalLayout createManageButtons(BucketRepository.BucketInfo bucket) { + private HorizontalLayout createManageButtons(Bucket bucket) { var layout = new HorizontalLayout(); { @@ -92,16 +94,16 @@ public class BucketList extends VerticalLayout { return layout; } - private void clickDetailsButton(BucketRepository.BucketInfo bucket) { + private void clickDetailsButton(Bucket bucket) { getUI().ifPresent(ui -> { ui.navigate("/nodes/" + nodeIdentifier + - "/buckets/" + bucket.identifier()); + "/buckets/" + bucket.getIdentifier()); }); } - private void clickRemoveButton(BucketRepository.BucketInfo bucket) { + private void clickRemoveButton(Bucket bucket) { var dialog = new Dialog("Confirm bucket deletion"); - dialog.add(new Paragraph("Confirm that you want to delete bucket. Enter '" + bucket.identifier() + "' to field below and confirm.")); + dialog.add(new Paragraph("Confirm that you want to delete bucket. Enter '" + bucket.getIdentifier() + "' to field below and confirm.")); var inputField = new TextField(); dialog.add(inputField); @@ -110,14 +112,14 @@ public class BucketList extends VerticalLayout { var button = new Button("Confirm"); button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR); button.addClickListener(event -> { - if (!bucket.identifier().equals(inputField.getValue())) { + if (!bucket.getIdentifier().equals(inputField.getValue())) { Notification.show("Invalid input", 3000, Notification.Position.TOP_END) .addThemeVariants(NotificationVariant.LUMO_ERROR); return; } removeBucket(bucket); - Notification.show("Bucket '" + bucket.identifier() + "' was successfully removed!", 3000, Notification.Position.TOP_END) + Notification.show("Bucket '" + bucket.getIdentifier() + "' was successfully removed!", 3000, Notification.Position.TOP_END) .addThemeVariants(NotificationVariant.LUMO_SUCCESS); dialog.close(); }); @@ -134,12 +136,14 @@ public class BucketList extends VerticalLayout { dialog.open(); } - public void update(List buckets) { + public void update(List buckets) { cachedBuckets = buckets; applySearch(searchField.getValue()); } - private void removeBucket(BucketRepository.BucketInfo bucket) { - // TODO: send remove request and getting list + private void removeBucket(Bucket bucket) { + if (removeMethod != null) { + removeMethod.accept(bucket); + } } } diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/Bucket.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/Bucket.java index 8c5e6e1..fb451c4 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/Bucket.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/Bucket.java @@ -1,12 +1,13 @@ package ru.dragonestia.loadbalancer.web.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; import ru.dragonestia.loadbalancer.web.model.type.SlotLimit; @Getter -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Bucket { private final String identifier; @@ -15,8 +16,21 @@ public class Bucket { private final String payload; private boolean locked = false; + @JsonCreator + private Bucket(@JsonProperty("identifier") String identifier, + @JsonProperty("nodeIdentifier") String nodeIdentifier, + @JsonProperty("slots") SlotLimit slots, + @JsonProperty("payload") String payload, + @JsonProperty("locked") boolean locked) { + this.identifier = identifier; + this.nodeIdentifier = nodeIdentifier; + this.slots = slots; + this.payload = payload; + this.locked = locked; + } + public static Bucket create(String identifier, Node node, SlotLimit limit, String payload) { - return new Bucket(identifier, node.identifier(), limit, payload); + return new Bucket(identifier, node.identifier(), limit, payload, false); } public void setLocked(boolean value) { @@ -26,7 +40,7 @@ public class Bucket { public boolean isAvailable(int usedSlots, int requiredSlots) { if (locked) return false; if (slots.isUnlimited()) return true; - return slots.getSlots() >= usedSlots + requiredSlots; + return slots.slots() >= usedSlots + requiredSlots; } @Override diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/type/SlotLimit.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/type/SlotLimit.java index 8da7618..c3f5320 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/type/SlotLimit.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/model/type/SlotLimit.java @@ -1,18 +1,11 @@ package ru.dragonestia.loadbalancer.web.model.type; -import lombok.Getter; +import java.beans.Transient; -@Getter -public class SlotLimit { +public record SlotLimit(int slots) { private final static int UNLIMITED_VALUE = -1; - private final int slots; - - private SlotLimit(int slots) { - this.slots = slots; - } - public static SlotLimit unlimited() { return new SlotLimit(UNLIMITED_VALUE); } @@ -21,6 +14,7 @@ public class SlotLimit { return new SlotLimit(slots); } + @Transient public boolean isUnlimited() { return slots == UNLIMITED_VALUE; } diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/BucketsPage.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/BucketsPage.java index f34b26c..710f281 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/BucketsPage.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/BucketsPage.java @@ -50,6 +50,6 @@ public class BucketsPage extends VerticalLayout implements BeforeEnterObserver { private void printBucketDetails() { add(new Html("Node identifier: " + bucket.getNodeIdentifier() + "")); add(new Html("Bucket identifier: " + bucket.getIdentifier() + "")); - add(new Html("Slots: " + (bucket.getSlots().isUnlimited()? "Unlimited" : bucket.getSlots().getSlots()) + "")); + add(new Html("Slots: " + (bucket.getSlots().isUnlimited()? "Unlimited" : bucket.getSlots().slots()) + "")); } } diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java index 1f31f3d..3120e7e 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java @@ -66,7 +66,7 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv initComponents(node, bucketRepository.all(node)); } - private void initComponents(Node node, List buckets) { + private void initComponents(Node node, List buckets) { printNodeDetails(node); add(new Hr()); add(registerBucket = new RegisterBucket(node, (bucket) -> { @@ -81,6 +81,10 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv })); add(new Hr()); add(bucketList = new BucketList(node.identifier(), buckets)); + bucketList.setRemoveMethod(bucket -> { + bucketRepository.remove(bucket); + bucketList.update(bucketRepository.all(node)); + }); } private void printNodeDetails(Node node) { diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/BucketRepository.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/BucketRepository.java index 0558dd4..806887e 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/BucketRepository.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/BucketRepository.java @@ -7,9 +7,9 @@ import java.util.List; public interface BucketRepository { - List all(Node node); + List all(Node node); void register(Bucket bucket); - record BucketInfo(String identifier, int slots) {} + void remove(Bucket bucket); } diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/BucketRepositoryImpl.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/BucketRepositoryImpl.java index 73e492c..d5f2970 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/BucketRepositoryImpl.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/BucketRepositoryImpl.java @@ -22,7 +22,7 @@ public class BucketRepositoryImpl implements BucketRepository { private final RestUtil rest; @Override - public List all(Node node) { + public List all(Node node) { var entity = rest.getEntity(URI.create("/nodes/" + node.identifier() + "/buckets"), BucketListResponse.class); @@ -44,12 +44,13 @@ public class BucketRepositoryImpl implements BucketRepository { BucketRegisterResponse.class, params -> { params.put("identifier", bucket.getIdentifier()); - params.put("slots", Integer.toString(bucket.getSlots().getSlots())); + params.put("slots", Integer.toString(bucket.getSlots().slots())); params.put("payload", bucket.getPayload()); params.put("locked", Boolean.toString(bucket.isLocked())); }); if (response.success()) return; + throw new Error(response.message()); } catch (HttpClientErrorException ex) { var response = ex.getResponseBodyAs(BucketRegisterResponse.class); @@ -61,4 +62,9 @@ public class BucketRepositoryImpl implements BucketRepository { throw new Error("Internal error. Check logs"); } } + + @Override + public void remove(Bucket bucket) { + rest.delete(URI.create("/nodes/" + bucket.getNodeIdentifier() + "/buckets/" + bucket.getIdentifier()), params -> {}); + } } diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/response/BucketListResponse.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/response/BucketListResponse.java index c3959df..c8df29f 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/response/BucketListResponse.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/repository/impl/response/BucketListResponse.java @@ -1,7 +1,7 @@ package ru.dragonestia.loadbalancer.web.repository.impl.response; -import ru.dragonestia.loadbalancer.web.repository.BucketRepository; +import ru.dragonestia.loadbalancer.web.model.Bucket; import java.util.List; -public record BucketListResponse(String node, List buckets) {} +public record BucketListResponse(String node, List buckets) {} diff --git a/src/main/java/ru/dragonestia/loadbalancer/controller/BucketController.java b/src/main/java/ru/dragonestia/loadbalancer/controller/BucketController.java index bce2d6e..4984620 100644 --- a/src/main/java/ru/dragonestia/loadbalancer/controller/BucketController.java +++ b/src/main/java/ru/dragonestia/loadbalancer/controller/BucketController.java @@ -11,6 +11,7 @@ import ru.dragonestia.loadbalancer.model.Bucket; import ru.dragonestia.loadbalancer.model.type.SlotLimit; import ru.dragonestia.loadbalancer.service.BucketService; import ru.dragonestia.loadbalancer.service.NodeService; +import ru.dragonestia.loadbalancer.util.NamingValidator; @Log4j2 @RestController @@ -25,9 +26,7 @@ public class BucketController { ResponseEntity allBuckets(@PathVariable(name = "nodeIdentifier") String nodeId) { var nodeOpt = nodeService.findNode(nodeId); return nodeOpt.map(node -> ResponseEntity.ok(new BucketListResponse(nodeId, - bucketService.allBuckets(node).stream() - .map(bucket -> new BucketListResponse.BucketInfo(bucket.getIdentifier(), bucket.getSlots().getSlots())) - .toList() + bucketService.allBuckets(node).stream().toList() ))).orElseGet(() -> ResponseEntity.notFound().build()); } @@ -56,4 +55,18 @@ public class BucketController { return ResponseEntity.status(500).body(new BucketRegisterResponse(false, ex.getMessage())); } } + + @DeleteMapping("/{identifier}") + ResponseEntity removeBucket(@PathVariable("nodeIdentifier") String nodeId, + @PathVariable("identifier") String bucketId) { + if (!NamingValidator.validateNodeIdentifier(nodeId) || !NamingValidator.validateBucketIdentifier(bucketId)) { + return ResponseEntity.ok().build(); + } + + var nodeOpt = nodeService.findNode(nodeId); + nodeOpt.flatMap(node -> bucketService.findBucket(node, bucketId)) + .ifPresent(bucketService::removeBucket); + + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/ru/dragonestia/loadbalancer/controller/response/BucketListResponse.java b/src/main/java/ru/dragonestia/loadbalancer/controller/response/BucketListResponse.java index 4f0481d..9b91917 100644 --- a/src/main/java/ru/dragonestia/loadbalancer/controller/response/BucketListResponse.java +++ b/src/main/java/ru/dragonestia/loadbalancer/controller/response/BucketListResponse.java @@ -1,8 +1,7 @@ package ru.dragonestia.loadbalancer.controller.response; +import ru.dragonestia.loadbalancer.model.Bucket; + import java.util.List; -public record BucketListResponse(String node, List buckets) { - - public record BucketInfo(String identifier, int slots) {} -} +public record BucketListResponse(String node, List buckets) {} diff --git a/src/main/java/ru/dragonestia/loadbalancer/model/type/SlotLimit.java b/src/main/java/ru/dragonestia/loadbalancer/model/type/SlotLimit.java index 7d6a6a9..0e448f5 100644 --- a/src/main/java/ru/dragonestia/loadbalancer/model/type/SlotLimit.java +++ b/src/main/java/ru/dragonestia/loadbalancer/model/type/SlotLimit.java @@ -2,6 +2,8 @@ package ru.dragonestia.loadbalancer.model.type; import lombok.Getter; +import java.beans.Transient; + @Getter public class SlotLimit { @@ -21,6 +23,7 @@ public class SlotLimit { return new SlotLimit(slots); } + @Transient public boolean isUnlimited() { return slots == UNLIMITED_VALUE; }