Implemented registration and getting buckets
This commit is contained in:
parent
d6d733e8f5
commit
96299218ec
@ -15,19 +15,21 @@ 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.Bucket;
|
import ru.dragonestia.loadbalancer.web.model.Bucket;
|
||||||
import ru.dragonestia.loadbalancer.web.repository.BucketRepository;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class BucketList extends VerticalLayout {
|
public class BucketList extends VerticalLayout {
|
||||||
|
|
||||||
private final String nodeIdentifier;
|
private final String nodeIdentifier;
|
||||||
private final Grid<BucketRepository.BucketInfo> bucketsGrid;
|
private final Grid<Bucket> bucketsGrid;
|
||||||
private final TextField searchField;
|
private final TextField searchField;
|
||||||
private List<BucketRepository.BucketInfo> cachedBuckets;
|
private List<Bucket> cachedBuckets;
|
||||||
|
@Setter private Consumer<Bucket> removeMethod;
|
||||||
|
|
||||||
public BucketList(String nodeIdentifier, List<BucketRepository.BucketInfo> buckets) {
|
public BucketList(String nodeIdentifier, List<Bucket> buckets) {
|
||||||
this.nodeIdentifier = nodeIdentifier;
|
this.nodeIdentifier = nodeIdentifier;
|
||||||
cachedBuckets = buckets;
|
cachedBuckets = buckets;
|
||||||
|
|
||||||
@ -51,20 +53,20 @@ public class BucketList extends VerticalLayout {
|
|||||||
var temp = input.trim();
|
var temp = input.trim();
|
||||||
|
|
||||||
bucketsGrid.setItems(cachedBuckets.stream()
|
bucketsGrid.setItems(cachedBuckets.stream()
|
||||||
.filter(bucket -> bucket.identifier().startsWith(temp))
|
.filter(bucket -> bucket.getIdentifier().startsWith(temp))
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Grid<BucketRepository.BucketInfo> createGrid() {
|
private Grid<Bucket> createGrid() {
|
||||||
var grid = new Grid<>(BucketRepository.BucketInfo.class, false);
|
var grid = new Grid<>(Bucket.class, false);
|
||||||
grid.addColumn(BucketRepository.BucketInfo::identifier).setHeader("Identifier");
|
grid.addColumn(Bucket::getIdentifier).setHeader("Identifier");
|
||||||
grid.addComponentColumn(bucket -> {
|
grid.addComponentColumn(bucket -> {
|
||||||
var result = new Span();
|
var result = new Span();
|
||||||
if (bucket.slots() == -1) {
|
if (bucket.getSlots().isUnlimited()) {
|
||||||
result.setText("Unlimited");
|
result.setText("Unlimited");
|
||||||
result.getElement().getThemeList().add("badge contrast");
|
result.getElement().getThemeList().add("badge contrast");
|
||||||
} else {
|
} else {
|
||||||
result.setText(Integer.toString(bucket.slots()));
|
result.setText(Integer.toString(bucket.getSlots().slots()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER);
|
}).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER);
|
||||||
@ -72,7 +74,7 @@ public class BucketList extends VerticalLayout {
|
|||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HorizontalLayout createManageButtons(BucketRepository.BucketInfo bucket) {
|
private HorizontalLayout createManageButtons(Bucket bucket) {
|
||||||
var layout = new HorizontalLayout();
|
var layout = new HorizontalLayout();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -92,16 +94,16 @@ public class BucketList extends VerticalLayout {
|
|||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clickDetailsButton(BucketRepository.BucketInfo bucket) {
|
private void clickDetailsButton(Bucket bucket) {
|
||||||
getUI().ifPresent(ui -> {
|
getUI().ifPresent(ui -> {
|
||||||
ui.navigate("/nodes/" + nodeIdentifier +
|
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");
|
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();
|
var inputField = new TextField();
|
||||||
dialog.add(inputField);
|
dialog.add(inputField);
|
||||||
@ -110,14 +112,14 @@ public class BucketList extends VerticalLayout {
|
|||||||
var button = new Button("Confirm");
|
var button = new Button("Confirm");
|
||||||
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
||||||
button.addClickListener(event -> {
|
button.addClickListener(event -> {
|
||||||
if (!bucket.identifier().equals(inputField.getValue())) {
|
if (!bucket.getIdentifier().equals(inputField.getValue())) {
|
||||||
Notification.show("Invalid input", 3000, Notification.Position.TOP_END)
|
Notification.show("Invalid input", 3000, Notification.Position.TOP_END)
|
||||||
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBucket(bucket);
|
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);
|
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
||||||
dialog.close();
|
dialog.close();
|
||||||
});
|
});
|
||||||
@ -134,12 +136,14 @@ public class BucketList extends VerticalLayout {
|
|||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(List<BucketRepository.BucketInfo> buckets) {
|
public void update(List<Bucket> buckets) {
|
||||||
cachedBuckets = buckets;
|
cachedBuckets = buckets;
|
||||||
applySearch(searchField.getValue());
|
applySearch(searchField.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeBucket(BucketRepository.BucketInfo bucket) {
|
private void removeBucket(Bucket bucket) {
|
||||||
// TODO: send remove request and getting list
|
if (removeMethod != null) {
|
||||||
|
removeMethod.accept(bucket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
package ru.dragonestia.loadbalancer.web.model;
|
package ru.dragonestia.loadbalancer.web.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
|
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
|
||||||
public class Bucket {
|
public class Bucket {
|
||||||
|
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
@ -15,8 +16,21 @@ public class Bucket {
|
|||||||
private final String payload;
|
private final String payload;
|
||||||
private boolean locked = false;
|
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) {
|
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) {
|
public void setLocked(boolean value) {
|
||||||
@ -26,7 +40,7 @@ public class Bucket {
|
|||||||
public boolean isAvailable(int usedSlots, int requiredSlots) {
|
public boolean isAvailable(int usedSlots, int requiredSlots) {
|
||||||
if (locked) return false;
|
if (locked) return false;
|
||||||
if (slots.isUnlimited()) return true;
|
if (slots.isUnlimited()) return true;
|
||||||
return slots.getSlots() >= usedSlots + requiredSlots;
|
return slots.slots() >= usedSlots + requiredSlots;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -1,18 +1,11 @@
|
|||||||
package ru.dragonestia.loadbalancer.web.model.type;
|
package ru.dragonestia.loadbalancer.web.model.type;
|
||||||
|
|
||||||
import lombok.Getter;
|
import java.beans.Transient;
|
||||||
|
|
||||||
@Getter
|
public record SlotLimit(int slots) {
|
||||||
public class SlotLimit {
|
|
||||||
|
|
||||||
private final static int UNLIMITED_VALUE = -1;
|
private final static int UNLIMITED_VALUE = -1;
|
||||||
|
|
||||||
private final int slots;
|
|
||||||
|
|
||||||
private SlotLimit(int slots) {
|
|
||||||
this.slots = slots;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SlotLimit unlimited() {
|
public static SlotLimit unlimited() {
|
||||||
return new SlotLimit(UNLIMITED_VALUE);
|
return new SlotLimit(UNLIMITED_VALUE);
|
||||||
}
|
}
|
||||||
@ -21,6 +14,7 @@ public class SlotLimit {
|
|||||||
return new SlotLimit(slots);
|
return new SlotLimit(slots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transient
|
||||||
public boolean isUnlimited() {
|
public boolean isUnlimited() {
|
||||||
return slots == UNLIMITED_VALUE;
|
return slots == UNLIMITED_VALUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,6 @@ public class BucketsPage extends VerticalLayout implements BeforeEnterObserver {
|
|||||||
private void printBucketDetails() {
|
private void printBucketDetails() {
|
||||||
add(new Html("<span>Node identifier: <b>" + bucket.getNodeIdentifier() + "</b></span>"));
|
add(new Html("<span>Node identifier: <b>" + bucket.getNodeIdentifier() + "</b></span>"));
|
||||||
add(new Html("<span>Bucket identifier: <b>" + bucket.getIdentifier() + "</b></span>"));
|
add(new Html("<span>Bucket identifier: <b>" + bucket.getIdentifier() + "</b></span>"));
|
||||||
add(new Html("<span>Slots: <b>" + (bucket.getSlots().isUnlimited()? "Unlimited" : bucket.getSlots().getSlots()) + "</b></span>"));
|
add(new Html("<span>Slots: <b>" + (bucket.getSlots().isUnlimited()? "Unlimited" : bucket.getSlots().slots()) + "</b></span>"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
|
|||||||
initComponents(node, bucketRepository.all(node));
|
initComponents(node, bucketRepository.all(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initComponents(Node node, List<BucketRepository.BucketInfo> buckets) {
|
private void initComponents(Node node, List<Bucket> buckets) {
|
||||||
printNodeDetails(node);
|
printNodeDetails(node);
|
||||||
add(new Hr());
|
add(new Hr());
|
||||||
add(registerBucket = new RegisterBucket(node, (bucket) -> {
|
add(registerBucket = new RegisterBucket(node, (bucket) -> {
|
||||||
@ -81,6 +81,10 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
|
|||||||
}));
|
}));
|
||||||
add(new Hr());
|
add(new Hr());
|
||||||
add(bucketList = new BucketList(node.identifier(), buckets));
|
add(bucketList = new BucketList(node.identifier(), buckets));
|
||||||
|
bucketList.setRemoveMethod(bucket -> {
|
||||||
|
bucketRepository.remove(bucket);
|
||||||
|
bucketList.update(bucketRepository.all(node));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printNodeDetails(Node node) {
|
private void printNodeDetails(Node node) {
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface BucketRepository {
|
public interface BucketRepository {
|
||||||
|
|
||||||
List<BucketInfo> all(Node node);
|
List<Bucket> all(Node node);
|
||||||
|
|
||||||
void register(Bucket bucket);
|
void register(Bucket bucket);
|
||||||
|
|
||||||
record BucketInfo(String identifier, int slots) {}
|
void remove(Bucket bucket);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class BucketRepositoryImpl implements BucketRepository {
|
|||||||
private final RestUtil rest;
|
private final RestUtil rest;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BucketInfo> all(Node node) {
|
public List<Bucket> all(Node node) {
|
||||||
var entity = rest.getEntity(URI.create("/nodes/" + node.identifier() + "/buckets"),
|
var entity = rest.getEntity(URI.create("/nodes/" + node.identifier() + "/buckets"),
|
||||||
BucketListResponse.class);
|
BucketListResponse.class);
|
||||||
|
|
||||||
@ -44,12 +44,13 @@ public class BucketRepositoryImpl implements BucketRepository {
|
|||||||
BucketRegisterResponse.class,
|
BucketRegisterResponse.class,
|
||||||
params -> {
|
params -> {
|
||||||
params.put("identifier", bucket.getIdentifier());
|
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("payload", bucket.getPayload());
|
||||||
params.put("locked", Boolean.toString(bucket.isLocked()));
|
params.put("locked", Boolean.toString(bucket.isLocked()));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.success()) return;
|
if (response.success()) return;
|
||||||
|
throw new Error(response.message());
|
||||||
} catch (HttpClientErrorException ex) {
|
} catch (HttpClientErrorException ex) {
|
||||||
var response = ex.getResponseBodyAs(BucketRegisterResponse.class);
|
var response = ex.getResponseBodyAs(BucketRegisterResponse.class);
|
||||||
|
|
||||||
@ -61,4 +62,9 @@ public class BucketRepositoryImpl implements BucketRepository {
|
|||||||
throw new Error("Internal error. Check logs");
|
throw new Error("Internal error. Check logs");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(Bucket bucket) {
|
||||||
|
rest.delete(URI.create("/nodes/" + bucket.getNodeIdentifier() + "/buckets/" + bucket.getIdentifier()), params -> {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package ru.dragonestia.loadbalancer.web.repository.impl.response;
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
public record BucketListResponse(String node, List<BucketRepository.BucketInfo> buckets) {}
|
public record BucketListResponse(String node, List<Bucket> buckets) {}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import ru.dragonestia.loadbalancer.model.Bucket;
|
|||||||
import ru.dragonestia.loadbalancer.model.type.SlotLimit;
|
import ru.dragonestia.loadbalancer.model.type.SlotLimit;
|
||||||
import ru.dragonestia.loadbalancer.service.BucketService;
|
import ru.dragonestia.loadbalancer.service.BucketService;
|
||||||
import ru.dragonestia.loadbalancer.service.NodeService;
|
import ru.dragonestia.loadbalancer.service.NodeService;
|
||||||
|
import ru.dragonestia.loadbalancer.util.NamingValidator;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@RestController
|
@RestController
|
||||||
@ -25,9 +26,7 @@ public class BucketController {
|
|||||||
ResponseEntity<BucketListResponse> allBuckets(@PathVariable(name = "nodeIdentifier") String nodeId) {
|
ResponseEntity<BucketListResponse> allBuckets(@PathVariable(name = "nodeIdentifier") String nodeId) {
|
||||||
var nodeOpt = nodeService.findNode(nodeId);
|
var nodeOpt = nodeService.findNode(nodeId);
|
||||||
return nodeOpt.map(node -> ResponseEntity.ok(new BucketListResponse(nodeId,
|
return nodeOpt.map(node -> ResponseEntity.ok(new BucketListResponse(nodeId,
|
||||||
bucketService.allBuckets(node).stream()
|
bucketService.allBuckets(node).stream().toList()
|
||||||
.map(bucket -> new BucketListResponse.BucketInfo(bucket.getIdentifier(), bucket.getSlots().getSlots()))
|
|
||||||
.toList()
|
|
||||||
))).orElseGet(() -> ResponseEntity.notFound().build());
|
))).orElseGet(() -> ResponseEntity.notFound().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,4 +55,18 @@ public class BucketController {
|
|||||||
return ResponseEntity.status(500).body(new BucketRegisterResponse(false, ex.getMessage()));
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
package ru.dragonestia.loadbalancer.controller.response;
|
package ru.dragonestia.loadbalancer.controller.response;
|
||||||
|
|
||||||
|
import ru.dragonestia.loadbalancer.model.Bucket;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record BucketListResponse(String node, List<BucketInfo> buckets) {
|
public record BucketListResponse(String node, List<Bucket> buckets) {}
|
||||||
|
|
||||||
public record BucketInfo(String identifier, int slots) {}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package ru.dragonestia.loadbalancer.model.type;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.beans.Transient;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class SlotLimit {
|
public class SlotLimit {
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ public class SlotLimit {
|
|||||||
return new SlotLimit(slots);
|
return new SlotLimit(slots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transient
|
||||||
public boolean isUnlimited() {
|
public boolean isUnlimited() {
|
||||||
return slots == UNLIMITED_VALUE;
|
return slots == UNLIMITED_VALUE;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user