View Javadoc
1   package de.dlr.shepard.common.filters;
2   
3   import de.dlr.shepard.auth.permission.services.PermissionsService;
4   import de.dlr.shepard.common.neo4j.io.HasIdIO;
5   import de.dlr.shepard.common.subscription.entities.Subscription;
6   import de.dlr.shepard.common.subscription.io.EventIO;
7   import de.dlr.shepard.common.subscription.io.SubscriptionIO;
8   import de.dlr.shepard.common.subscription.services.SubscriptionService;
9   import de.dlr.shepard.common.util.AccessType;
10  import de.dlr.shepard.common.util.HasId;
11  import de.dlr.shepard.common.util.RequestMethod;
12  import io.quarkus.logging.Log;
13  import jakarta.enterprise.context.RequestScoped;
14  import jakarta.inject.Inject;
15  import jakarta.ws.rs.ProcessingException;
16  import jakarta.ws.rs.client.ClientBuilder;
17  import jakarta.ws.rs.client.Entity;
18  import jakarta.ws.rs.container.ContainerRequestContext;
19  import jakarta.ws.rs.container.ContainerResponseContext;
20  import jakarta.ws.rs.container.ContainerResponseFilter;
21  import jakarta.ws.rs.core.MediaType;
22  import jakarta.ws.rs.ext.Provider;
23  import java.util.List;
24  import java.util.regex.Pattern;
25  
26  @Subscribable
27  @Provider
28  @RequestScoped
29  public class SubscriptionFilter implements ContainerResponseFilter {
30  
31    @Inject
32    ExecutorFactory executorFactory;
33  
34    @Inject
35    PermissionsService permissionsService;
36  
37    @Inject
38    SubscriptionService subscriptionService;
39  
40    @Override
41    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
42      // request not successful
43      var status = responseContext.getStatus();
44      if (!(status >= 200 && status < 300)) {
45        Log.debug("Skip subscriptions since the http status code is not between 200 and 299");
46        return;
47      }
48  
49      // request successful
50      EventIO event = new EventIO(
51        requestContext.getUriInfo().getAbsolutePath().toString(),
52        RequestMethod.valueOf(requestContext.getMethod())
53      );
54  
55      Object entity = responseContext.getEntity();
56      if (entity instanceof HasId hasId) {
57        event.setSubscribedObject(new HasIdIO(hasId));
58      }
59  
60      List<Subscription> subs = subscriptionService.getMatchingSubscriptions(event.getRequestMethod());
61      for (Subscription sub : subs) {
62        // TODO: This could develop into a bottleneck
63        Pattern pattern = Pattern.compile(sub.getSubscribedURL());
64        if (
65          pattern.matcher(event.getUrl()).matches() &&
66          permissionsService.isAllowed(requestContext, AccessType.Read, sub.getCreatedBy().getUsername())
67        ) {
68          EventIO e = new EventIO(event);
69          e.setSubscription(new SubscriptionIO(sub));
70          Log.debugf("%s was triggered with %s", sub, e);
71          executorFactory.getInstance().execute(() -> sendCallback(sub, e));
72        }
73      }
74    }
75  
76    private void sendCallback(Subscription sub, EventIO event) {
77      var client = ClientBuilder.newClient();
78      var webTarget = client.target(sub.getCallbackURL());
79  
80      try {
81        var entity = Entity.entity(event, MediaType.APPLICATION_JSON);
82        var response = webTarget.request().buildPost(entity).invoke();
83        Log.infof("Notification has been send to %s with response code: %s", sub.getCallbackURL(), response.getStatus());
84      } catch (ProcessingException e) {
85        Log.error("Could not execute notification request");
86      } finally {
87        client.close();
88      }
89    }
90  }