From d307fdbe83b72e88e96cd7c5a19fd4c204433e62 Mon Sep 17 00:00:00 2001
From: JerichoFletcher <jericho.russel17@gmail.com>
Date: Mon, 13 Nov 2023 10:17:34 +0700
Subject: [PATCH] feat: middleware via handlers

---
 src/main/java/com/bnmoboxd/Main.java          |  7 +-
 .../controllers/SubscriptionController.java   | 95 +++++--------------
 .../com/bnmoboxd/{config => core}/Config.java |  2 +-
 .../java/com/bnmoboxd/core/Endpoints.java     | 30 ++++++
 .../java/com/bnmoboxd/database/Database.java  |  2 +-
 .../com/bnmoboxd/handlers/AuthHandler.java    | 31 ++++++
 .../com/bnmoboxd/handlers/LoggingHandler.java | 34 +++++++
 .../bnmoboxd/middlewares/AuthMiddleware.java  | 28 ++++--
 .../middlewares/LoggingMiddleware.java        | 74 +++++++++------
 .../bnmoboxd/repositories/LogRepository.java  | 26 +++--
 .../repositories/SubscriptionRepository.java  | 18 ++--
 .../services/SubscriptionService.java         | 12 +--
 src/main/java/com/bnmoboxd/struct/Pair.java   | 11 ---
 .../controllers/SubscriptionHandlers.xml      | 13 +++
 14 files changed, 235 insertions(+), 148 deletions(-)
 rename src/main/java/com/bnmoboxd/{config => core}/Config.java (88%)
 create mode 100644 src/main/java/com/bnmoboxd/core/Endpoints.java
 create mode 100644 src/main/java/com/bnmoboxd/handlers/AuthHandler.java
 create mode 100644 src/main/java/com/bnmoboxd/handlers/LoggingHandler.java
 delete mode 100644 src/main/java/com/bnmoboxd/struct/Pair.java
 create mode 100644 src/main/resources/com/bnmoboxd/controllers/SubscriptionHandlers.xml

diff --git a/src/main/java/com/bnmoboxd/Main.java b/src/main/java/com/bnmoboxd/Main.java
index 3390395..b7271b5 100644
--- a/src/main/java/com/bnmoboxd/Main.java
+++ b/src/main/java/com/bnmoboxd/Main.java
@@ -1,14 +1,13 @@
 package com.bnmoboxd;
 
 import com.bnmoboxd.controllers.SubscriptionController;
-
-import javax.xml.ws.*;
+import com.bnmoboxd.core.Endpoints;
 
 public class Main {
     public static void main(String[] args){
         try {
-            Endpoint.publish("http://localhost:9000/subscription", new SubscriptionController());
-            System.out.println("Server created at localhost:9000");
+            Endpoints.publish("/subscription", new SubscriptionController());
+            System.out.printf("Server created at %s%n", Endpoints.getHost());
         } catch (Exception e) {
             e.printStackTrace();
         }
diff --git a/src/main/java/com/bnmoboxd/controllers/SubscriptionController.java b/src/main/java/com/bnmoboxd/controllers/SubscriptionController.java
index 3d5ad42..de30f59 100644
--- a/src/main/java/com/bnmoboxd/controllers/SubscriptionController.java
+++ b/src/main/java/com/bnmoboxd/controllers/SubscriptionController.java
@@ -1,12 +1,9 @@
 package com.bnmoboxd.controllers;
 
-import com.bnmoboxd.middlewares.AuthMiddleware;
-import com.bnmoboxd.middlewares.LoggingMiddleware;
 import com.bnmoboxd.models.Subscription;
 import com.bnmoboxd.repositories.SubscriptionRepository;
 import com.bnmoboxd.services.SubscriptionService;
 import com.bnmoboxd.struct.Pagination;
-import com.bnmoboxd.struct.Pair;
 import com.bnmoboxd.struct.SubscriptionStatus;
 
 import javax.annotation.Resource;
@@ -16,12 +13,12 @@ import javax.xml.ws.WebServiceContext;
 import java.util.List;
 
 @WebService
+@HandlerChain(file = "SubscriptionHandlers.xml")
 public class SubscriptionController {
     private final SubscriptionService subscriptionService;
     @Resource
     private WebServiceContext serviceContext;
 
-    // TODO: Logging
     public SubscriptionController() {
         subscriptionService = new SubscriptionService();
     }
@@ -35,17 +32,8 @@ public class SubscriptionController {
         @WebParam(name = "take")
         Integer take
     ) {
-        if(new AuthMiddleware(serviceContext).execute()) {
-            new LoggingMiddleware(serviceContext,
-                new Pair<>("endpoint", "/subscription"),
-                new Pair<>("page", page),
-                new Pair<>("take", take)
-            ).execute();
-            Pagination pagination = page != null && take != null ? new Pagination(page, take) : null;
-            return subscriptionService.getSubscriptions(null, pagination);
-        } else {
-            return null;
-        }
+        Pagination pagination = page != null && take != null ? new Pagination(page, take) : null;
+        return subscriptionService.getSubscriptions(null, pagination);
     }
 
     @WebMethod(operationName = "count")
@@ -55,19 +43,12 @@ public class SubscriptionController {
         @XmlElement(required = true)
         String curatorUsername
     ) {
-        if(new AuthMiddleware(serviceContext).execute() && curatorUsername != null) {
-            new LoggingMiddleware(serviceContext,
-                new Pair<>("endpoint", "/subscription"),
-                new Pair<>("curatorUsername", curatorUsername)
-            ).execute();
-            return subscriptionService.getSubscriptions(new SubscriptionRepository.Filter(
-                curatorUsername,
-                null,
-                SubscriptionStatus.ACCEPTED
-            )).size();
-        } else {
-            return null;
-        }
+        return subscriptionService.getSubscriptions(new SubscriptionRepository.Filter(
+            curatorUsername,
+            null,
+            SubscriptionStatus.ACCEPTED
+        )).size();
+
     }
 
     @WebMethod(operationName = "add")
@@ -85,25 +66,11 @@ public class SubscriptionController {
         @XmlElement(required = true)
         String status
     ) {
-        if(new AuthMiddleware(serviceContext).execute()
-            && curatorUsername != null
-            && subscriberUsername != null
-            && status != null
-        ) {
-            new LoggingMiddleware(serviceContext,
-                new Pair<>("endpoint", "/subscription"),
-                new Pair<>("curatorUsername", curatorUsername),
-                new Pair<>("subscriberUsername", subscriberUsername),
-                new Pair<>("status", status)
-            ).execute();
-            return subscriptionService.addSubscription(
-                curatorUsername,
-                subscriberUsername,
-                SubscriptionStatus.valueOf(status)
-            );
-        } else {
-            return null;
-        }
+        return subscriptionService.addSubscription(
+            curatorUsername,
+            subscriberUsername,
+            SubscriptionStatus.valueOf(status)
+        );
     }
 
     @WebMethod(operationName = "update")
@@ -121,30 +88,16 @@ public class SubscriptionController {
         @XmlElement(required = true)
         String status
     ) {
-        if(new AuthMiddleware(serviceContext).execute()
-            && curatorUsername != null
-            && subscriberUsername != null
-            && status != null
-        ) {
-            new LoggingMiddleware(serviceContext,
-                new Pair<>("endpoint", "/subscription"),
-                new Pair<>("curatorUsername", curatorUsername),
-                new Pair<>("subscriberUsername", subscriberUsername),
-                new Pair<>("status", status)
-            ).execute();
-            try {
-                SubscriptionStatus newStatus = SubscriptionStatus.valueOf(status);
-                return subscriptionService.updateSubscription(
-                    curatorUsername,
-                    subscriberUsername,
-                    newStatus
-                );
-            } catch(IllegalArgumentException e) {
-                e.printStackTrace();
-                return null;
-            }
-        } else {
-            return null;
+        try {
+            SubscriptionStatus newStatus = SubscriptionStatus.valueOf(status);
+            return subscriptionService.updateSubscription(
+                curatorUsername,
+                subscriberUsername,
+                newStatus
+            );
+        } catch(IllegalArgumentException e) {
+            e.printStackTrace();
+            return false;
         }
     }
 }
diff --git a/src/main/java/com/bnmoboxd/config/Config.java b/src/main/java/com/bnmoboxd/core/Config.java
similarity index 88%
rename from src/main/java/com/bnmoboxd/config/Config.java
rename to src/main/java/com/bnmoboxd/core/Config.java
index f7b0c0d..688a2cf 100644
--- a/src/main/java/com/bnmoboxd/config/Config.java
+++ b/src/main/java/com/bnmoboxd/core/Config.java
@@ -1,4 +1,4 @@
-package com.bnmoboxd.config;
+package com.bnmoboxd.core;
 
 import io.github.cdimascio.dotenv.Dotenv;
 
diff --git a/src/main/java/com/bnmoboxd/core/Endpoints.java b/src/main/java/com/bnmoboxd/core/Endpoints.java
new file mode 100644
index 0000000..b3e9f1f
--- /dev/null
+++ b/src/main/java/com/bnmoboxd/core/Endpoints.java
@@ -0,0 +1,30 @@
+package com.bnmoboxd.core;
+
+import javax.xml.ws.Endpoint;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Endpoints {
+    private static final String host = "http://localhost:9000";
+//    private static final Map<String, Object> endpoint2Executor = new HashMap<>();
+    private static final Map<String, String> executor2Endpoint = new HashMap<>();
+
+    public static String getHost() {
+        return host;
+    }
+
+    public static void publish(String endpointAddress, Object executor) {
+//        endpoint2Executor.put(endpointAddress, executor);
+        executor2Endpoint.put(executor.getClass().getName(), endpointAddress);
+
+        Endpoint.publish(host + endpointAddress, executor);
+    }
+
+    public static String getEndpoint(String executorName) {
+        return executor2Endpoint.get(executorName);
+    }
+
+    public static String getEndpoint(Object executor) {
+        return executor2Endpoint.get(executor.getClass().getName());
+    }
+}
diff --git a/src/main/java/com/bnmoboxd/database/Database.java b/src/main/java/com/bnmoboxd/database/Database.java
index f87ebb7..2182ca9 100644
--- a/src/main/java/com/bnmoboxd/database/Database.java
+++ b/src/main/java/com/bnmoboxd/database/Database.java
@@ -1,6 +1,6 @@
 package com.bnmoboxd.database;
 
-import com.bnmoboxd.config.Config;
+import com.bnmoboxd.core.Config;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
diff --git a/src/main/java/com/bnmoboxd/handlers/AuthHandler.java b/src/main/java/com/bnmoboxd/handlers/AuthHandler.java
new file mode 100644
index 0000000..6c8ae2e
--- /dev/null
+++ b/src/main/java/com/bnmoboxd/handlers/AuthHandler.java
@@ -0,0 +1,31 @@
+package com.bnmoboxd.handlers;
+
+import com.bnmoboxd.middlewares.AuthMiddleware;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPHandler;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+import java.util.Collections;
+import java.util.Set;
+
+public class AuthHandler implements SOAPHandler<SOAPMessageContext> {
+    @Override
+    public Set<QName> getHeaders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean handleMessage(SOAPMessageContext context) {
+        return (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY) || new AuthMiddleware(context).execute();
+    }
+
+    @Override
+    public boolean handleFault(SOAPMessageContext context) {
+        return true;
+    }
+
+    @Override
+    public void close(MessageContext context) {
+    }
+}
diff --git a/src/main/java/com/bnmoboxd/handlers/LoggingHandler.java b/src/main/java/com/bnmoboxd/handlers/LoggingHandler.java
new file mode 100644
index 0000000..4f5771f
--- /dev/null
+++ b/src/main/java/com/bnmoboxd/handlers/LoggingHandler.java
@@ -0,0 +1,34 @@
+package com.bnmoboxd.handlers;
+
+import com.bnmoboxd.middlewares.LoggingMiddleware;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPHandler;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+import java.util.Collections;
+import java.util.Set;
+
+public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {
+    @Override
+    public Set<QName> getHeaders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean handleMessage(SOAPMessageContext context) {
+        if(!(Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
+            new LoggingMiddleware(context).execute();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean handleFault(SOAPMessageContext context) {
+        return true;
+    }
+
+    @Override
+    public void close(MessageContext context) {
+    }
+}
diff --git a/src/main/java/com/bnmoboxd/middlewares/AuthMiddleware.java b/src/main/java/com/bnmoboxd/middlewares/AuthMiddleware.java
index 1909098..df0a01a 100644
--- a/src/main/java/com/bnmoboxd/middlewares/AuthMiddleware.java
+++ b/src/main/java/com/bnmoboxd/middlewares/AuthMiddleware.java
@@ -1,26 +1,42 @@
 package com.bnmoboxd.middlewares;
 
-import com.bnmoboxd.config.Config;
+import com.bnmoboxd.core.Config;
+import com.bnmoboxd.core.Endpoints;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.xml.internal.ws.developer.JAXWSProperties;
 import lombok.AllArgsConstructor;
 
-import javax.xml.ws.WebServiceContext;
+import javax.xml.namespace.QName;
 import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
 
 @SuppressWarnings("unchecked")
 @AllArgsConstructor
 public class AuthMiddleware implements Middleware {
-    private final WebServiceContext serviceContext;
+    private final SOAPMessageContext context;
 
     @Override
     public boolean execute() {
-        MessageContext msgContext = serviceContext.getMessageContext();
-        Map<String, Object> headers = (Map<String, Object>) msgContext.get(MessageContext.HTTP_REQUEST_HEADERS);
+        Map<String, Object> headers = (Map<String, Object>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
 
         try {
             String apiKey = ((List<String>) headers.get("x-api-key")).get(0);
-            return apiKey != null && apiKey.equals(Config.get("SOAP_API_KEY"));
+            boolean auth = apiKey != null && apiKey.equals(Config.get("SOAP_API_KEY"));
+
+            String endpoint = Endpoints.getEndpoint(String.format("com.bnmoboxd.controllers.%s",
+                ((QName) context.get(MessageContext.WSDL_INTERFACE)).getLocalPart()
+            ));
+            String method = ((QName) context.get(MessageContext.WSDL_OPERATION)).getLocalPart();
+            HttpExchange exchange = (HttpExchange) context.get(JAXWSProperties.HTTP_EXCHANGE);
+            String client = String.format("%s:%s", exchange.getRemoteAddress().getAddress(), exchange.getRemoteAddress().getPort());
+
+            System.out.printf("[%s %16s: %-8s] %-20s client: %s; auth: %s;%n",
+                LocalDateTime.now(), endpoint, method, getClass().getSimpleName(), client, auth
+            );
+            return auth;
         } catch(Exception e) {
             e.printStackTrace();
         }
diff --git a/src/main/java/com/bnmoboxd/middlewares/LoggingMiddleware.java b/src/main/java/com/bnmoboxd/middlewares/LoggingMiddleware.java
index d14824c..c9b0635 100644
--- a/src/main/java/com/bnmoboxd/middlewares/LoggingMiddleware.java
+++ b/src/main/java/com/bnmoboxd/middlewares/LoggingMiddleware.java
@@ -1,54 +1,70 @@
 package com.bnmoboxd.middlewares;
-
-import com.bnmoboxd.struct.Pair;
+import com.bnmoboxd.core.Endpoints;
+import com.bnmoboxd.repositories.LogRepository;
+import com.sun.net.httpserver.HttpExchange;
 import com.sun.xml.internal.ws.developer.JAXWSProperties;
-import com.sun.xml.internal.ws.server.WSEndpointImpl;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
-import javax.xml.ws.WebServiceContext;
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPBody;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
 import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
 import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.Map;
 
 @SuppressWarnings("unchecked")
 public class LoggingMiddleware implements Middleware {
-    private final WebServiceContext serviceContext;
-    private final Pair<String, Object>[] params;
+    private final SOAPMessageContext context;
+    private final LogRepository logRepository;
 
-    @SafeVarargs
-    public LoggingMiddleware(WebServiceContext serviceContext, Pair<String, Object>... params) {
-        this.serviceContext = serviceContext;
-        this.params = params;
+    public LoggingMiddleware(SOAPMessageContext context) {
+        this.context = context;
+        this.logRepository = new LogRepository();
     }
 
     @Override
     public boolean execute() {
-        // TODO: Do this the better way: call this from a Handler?
-        MessageContext msgContext = serviceContext.getMessageContext();
-        Map<String, Object> headers = (Map<String, Object>) msgContext.get(MessageContext.HTTP_REQUEST_HEADERS);
+        String endpoint = Endpoints.getEndpoint(String.format("com.bnmoboxd.controllers.%s",
+            ((QName) context.get(MessageContext.WSDL_INTERFACE)).getLocalPart()
+        ));
+        String method = ((QName) context.get(MessageContext.WSDL_OPERATION)).getLocalPart();
+        HttpExchange exchange = (HttpExchange) context.get(JAXWSProperties.HTTP_EXCHANGE);
+        String client = String.format("%s:%s", exchange.getRemoteAddress().getAddress(), exchange.getRemoteAddress().getPort());
+        String params = buildParamString(context.getMessage());
+
+        logRepository.addLog(params, endpoint, client, method);
+
+        System.out.printf("[%s %16s: %-8s] %-20s client: %s; %s%n",
+            LocalDateTime.now(), endpoint, method, getClass().getSimpleName(), client, params
+        );
+        return true;
+    }
 
+    private String buildParamString(SOAPMessage message) {
         try {
-            String endpoint = (String) getParam("endpoint");
-            String method = msgContext.get(MessageContext.WSDL_OPERATION).toString();
-            method = method.substring(method.indexOf('}') + 1);
-
-            StringBuilder paramsStr = new StringBuilder();
-            for(Pair<String, Object> param : params) {
-                if(paramsStr.length() > 0) paramsStr.append(';');
-                paramsStr.append(String.format(" %s: %s", param.getFirst(), param.getSecond()));
-            }
+            StringBuilder str = new StringBuilder();
+
+            SOAPBody body = context.getMessage().getSOAPBody();
+            NodeList children = body.getFirstChild().getChildNodes();
 
-            System.out.printf("[%s %8s]%s%n", LocalDateTime.now(), method, paramsStr);
-        } catch(Exception e) {
+            for(int i = 0; i < children.getLength(); i++) {
+                Node child = children.item(i);
+                if(str.length() > 0) str.append(' ');
+                str.append(String.format("%s: %s;", child.getLocalName(), child.getTextContent()));
+            }
+            return str.toString();
+        } catch(SOAPException e) {
             e.printStackTrace();
+            return "";
         }
-        return true;
     }
 
-    private Object getParam(String key) {
+    /*private Object getParam(String key) {
         for(Pair<String, Object> param : params) {
             if(param.getFirst().equals(key)) return param.getSecond();
         }
         return null;
-    }
+    }*/
 }
diff --git a/src/main/java/com/bnmoboxd/repositories/LogRepository.java b/src/main/java/com/bnmoboxd/repositories/LogRepository.java
index 62f7a2a..868011c 100644
--- a/src/main/java/com/bnmoboxd/repositories/LogRepository.java
+++ b/src/main/java/com/bnmoboxd/repositories/LogRepository.java
@@ -2,6 +2,7 @@ package com.bnmoboxd.repositories;
 
 import com.bnmoboxd.database.Database;
 import com.bnmoboxd.models.Log;
+import com.bnmoboxd.struct.SubscriptionStatus;
 
 import java.sql.Connection;
 import java.sql.PreparedStatement;
@@ -12,10 +13,6 @@ import java.util.List;
 
 public class LogRepository {
     public List<Log> getAllLogs() {
-        /*
-         * Could be improved to be tidier
-         * The try catch block isn't very nice looking ?
-         * */
         try(Connection connection = Database.getConnection()) {
             String query = "SELECT * FROM logs";
             List<Log> logs = new ArrayList<>();
@@ -31,8 +28,6 @@ public class LogRepository {
 
                     Log log = new Log(id, description, endpoint, clientIp, requestTimestamp, soapRequest);
                     logs.add(log);
-                    /*System.out.println(log.getId());
-                    System.out.println(log.getDescription());*/
                 }
             }
             return logs;
@@ -41,4 +36,23 @@ public class LogRepository {
             return null;
         }
     }
+
+    public boolean addLog(String description, String endpoint, String clientIp, String soapRequest) {
+        try(Connection connection = Database.getConnection()) {
+            String query = "INSERT INTO logs(description, endpoint, client_ip, soap_request) VALUES (?, ?, ?, ?)";
+
+            try(PreparedStatement statement = connection.prepareStatement(query)) {
+                statement.setString(1, description);
+                statement.setString(2, endpoint);
+                statement.setString(3, clientIp);
+                statement.setString(4, soapRequest);
+
+                int rowCount = statement.executeUpdate();
+                return rowCount > 0;
+            }
+        } catch(SQLException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
 }
diff --git a/src/main/java/com/bnmoboxd/repositories/SubscriptionRepository.java b/src/main/java/com/bnmoboxd/repositories/SubscriptionRepository.java
index ca4ab1d..7869da6 100644
--- a/src/main/java/com/bnmoboxd/repositories/SubscriptionRepository.java
+++ b/src/main/java/com/bnmoboxd/repositories/SubscriptionRepository.java
@@ -65,16 +65,16 @@ public class SubscriptionRepository {
         }
     }
 
-    public boolean addSubscription(Subscription subscription) {
+    public boolean addSubscription(String curatorUsername, String subscriberUsername, SubscriptionStatus status) {
         try(Connection connection = Database.getConnection()) {
             String query = "INSERT INTO subscriptions VALUES (?, ?, ?)";
 
             try(PreparedStatement statement = connection.prepareStatement(query)) {
-                statement.setString(1, subscription.getCuratorUsername());
-                statement.setString(2, subscription.getSubscriberUsername());
-                statement.setString(3, subscription.getStatus().toString());
+                statement.setString(1, curatorUsername);
+                statement.setString(2, subscriberUsername);
+                statement.setString(3, status.toString());
 
-                // Will fail if a subscription already exists
+                // Will return 0 if a subscription already exists
                 int rowCount = statement.executeUpdate();
                 return rowCount > 0;
             }
@@ -84,14 +84,14 @@ public class SubscriptionRepository {
         }
     }
 
-    public boolean updateSubscription(Subscription subscription) {
+    public boolean updateSubscription(String curatorUsername, String subscriberUsername, SubscriptionStatus status) {
         try(Connection connection = Database.getConnection()) {
             String query = "UPDATE subscriptions SET status = ? WHERE curator_username = ? AND subscriber_username = ?";
 
             try(PreparedStatement statement = connection.prepareStatement(query)) {
-                statement.setString(1, subscription.getStatus().toString());
-                statement.setString(2, subscription.getCuratorUsername());
-                statement.setString(3, subscription.getSubscriberUsername());
+                statement.setString(1, status.toString());
+                statement.setString(2, curatorUsername);
+                statement.setString(3, subscriberUsername);
 
                 int rowCount = statement.executeUpdate();
                 return rowCount > 0;
diff --git a/src/main/java/com/bnmoboxd/services/SubscriptionService.java b/src/main/java/com/bnmoboxd/services/SubscriptionService.java
index 3e00b5c..bceb26c 100644
--- a/src/main/java/com/bnmoboxd/services/SubscriptionService.java
+++ b/src/main/java/com/bnmoboxd/services/SubscriptionService.java
@@ -23,18 +23,10 @@ public class SubscriptionService {
     }
 
     public boolean addSubscription(String curatorUsername, String subscriberUsername, SubscriptionStatus status) {
-        return subscriptionRepository.addSubscription(new Subscription(
-            curatorUsername,
-            subscriberUsername,
-            status
-        ));
+        return subscriptionRepository.addSubscription(curatorUsername, subscriberUsername, status);
     }
 
     public boolean updateSubscription(String curatorUsername, String subscriberUsername, SubscriptionStatus status) {
-        return subscriptionRepository.updateSubscription(new Subscription(
-            curatorUsername,
-            subscriberUsername,
-            status
-        ));
+        return subscriptionRepository.updateSubscription(curatorUsername, subscriberUsername, status);
     }
 }
diff --git a/src/main/java/com/bnmoboxd/struct/Pair.java b/src/main/java/com/bnmoboxd/struct/Pair.java
deleted file mode 100644
index 91a4c62..0000000
--- a/src/main/java/com/bnmoboxd/struct/Pair.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.bnmoboxd.struct;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-@Getter
-@AllArgsConstructor
-public class Pair<T1, T2> {
-    private T1 first;
-    private T2 second;
-}
diff --git a/src/main/resources/com/bnmoboxd/controllers/SubscriptionHandlers.xml b/src/main/resources/com/bnmoboxd/controllers/SubscriptionHandlers.xml
new file mode 100644
index 0000000..a228d1c
--- /dev/null
+++ b/src/main/resources/com/bnmoboxd/controllers/SubscriptionHandlers.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
+    <handler-chain>
+        <handler>
+            <handler-name>com.bnmoboxd.handlers.LoggingHandler</handler-name>
+            <handler-class>com.bnmoboxd.handlers.LoggingHandler</handler-class>
+        </handler>
+        <handler>
+            <handler-name>com.bnmoboxd.handlers.AuthHandler</handler-name>
+            <handler-class>com.bnmoboxd.handlers.AuthHandler</handler-class>
+        </handler>
+    </handler-chain>
+</handler-chains>
\ No newline at end of file
-- 
GitLab