opinionated-vertx/src/main/java/de/pzzz/vertx/RestDataAccess.java
2026-03-25 15:33:46 +01:00

196 lines
5.7 KiB
Java

package de.pzzz.vertx;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.json.Json;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
public class RestDataAccess<T extends SerializableWithId> {
private Map<String, T> dataMap = new ConcurrentHashMap<>();
protected final Class<T> classReference;
public RestDataAccess(final Class<T> classReference) {
this.classReference = classReference;
}
public void registerRoutes(final Router router, final String baseUrl) {
router.get(baseUrl).handler(this::list);
router.post(baseUrl).handler(this::add);
router.get(baseUrl + "/:id").handler(this::get);
router.put(baseUrl + "/:id").handler(this::update);
router.delete(baseUrl + "/:id").handler(this::delete);
}
/**
* Returns bus address.
*
* @param vertx
* @return
*/
public String setupConsumer(final Vertx vertx) {
final String busAddress = this.getClass().getName() + "." + UUID.randomUUID();
MessageConsumer<RestDataRequest<T>> consumer = vertx.eventBus()
.consumer(busAddress);
consumer.handler(this::handleMessage);
return busAddress;
}
public Collection<T> list() {
return dataMap.values();
}
public T get(final String id) {
return dataMap.get(id);
}
public boolean contains(final String id) {
return dataMap.containsKey(id);
}
public void add(final T data) {
dataMap.put(data.getId(), data);
}
public void update(final T newData) {
dataMap.put(newData.getId(), newData);
}
public void delete(final String id) {
dataMap.remove(id);
}
protected void update(final String id, final RoutingContext context) {
T newData = context.body().asPojo(classReference);
if (!newData.getId().equals(id)) {
context.fail(400);
}
update(newData);
}
protected T getDataFromRequest(final RoutingContext context) {
return context.body().asPojo(classReference);
}private void handleMessage(final Message<RestDataRequest<T>> request) {
try {
RestDataRequest<T> req = request.body();
switch (req.getCommand()) {
case LIST -> handleList(request);
case GET -> handleGet(request, req.getId());
case ADD -> handleAdd(request, req.getData());
case UPDATE -> handleUpdate(request, req.getData());
case DELETE -> handleDelete(request, req.getId());
default -> request.fail(500, "Unsupported request type");
}
} catch (Exception e) {
request.fail(500, "Internal server error: " + e.getMessage());
}
}
private void handleList(Message<RestDataRequest<T>> request) {
request.reply(new ArrayList<>(list()));
}
private void handleGet(Message<RestDataRequest<T>> request, String id) {
T data = get(id);
if (data == null) {
request.fail(404, "Not found");
} else {
request.reply(data);
}
}
private void handleAdd(Message<RestDataRequest<T>> request, T data) {
if (data == null) {
request.fail(400, "No data provided");
} else {
add(data);
request.reply(data.getId());
}
}
private void handleUpdate(Message<RestDataRequest<T>> request, T data) {
if (data == null || !contains(data.getId())) {
request.fail(400, "Invalid data or ID not found");
} else {
update(data);
request.reply(data.getId());
}
}
private void handleDelete(Message<RestDataRequest<T>> request, String id) {
if (id == null || !contains(id)) {
request.fail(404, "Not found");
} else {
delete(id);
request.reply(true);
}
}
private void list(final RoutingContext context) {
if (context.response().ended()) {
return;
}
context.response().end(Json.encodePrettily(list()));
}
private void add(final RoutingContext context) {
if (context.response().ended()) {
return;
}
T data = getDataFromRequest(context);
if (context.response().ended()) {
return;
}
add(data);
context.response().setStatusCode(201).end();
}
private void get(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!dataMap.containsKey(id)) {
context.fail(404);
return;
}
context.response().end(Json.encodePrettily(get(id)));
}
private void update(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!dataMap.containsKey(id)) {
context.fail(404);
return;
}
update(id, context);
if (context.response().ended()) {
return;
}
context.response().setStatusCode(204).end();
}
private void delete(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!dataMap.containsKey(id)) {
context.fail(404);
return;
}
delete(id);
context.response().setStatusCode(204).end();
}
}