NotificationResource.java

1
package com.reallifedeveloper.common.resource.notification;
2
3
import static com.reallifedeveloper.common.domain.LogUtil.removeCRLF;
4
5
import java.util.ArrayList;
6
import java.util.List;
7
import java.util.Optional;
8
9
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
10
import jakarta.ws.rs.GET;
11
import jakarta.ws.rs.Path;
12
import jakarta.ws.rs.PathParam;
13
import jakarta.ws.rs.Produces;
14
import jakarta.ws.rs.core.Context;
15
import jakarta.ws.rs.core.Link;
16
import jakarta.ws.rs.core.MediaType;
17
import jakarta.ws.rs.core.Response;
18
import jakarta.ws.rs.core.UriBuilder;
19
import jakarta.ws.rs.core.UriInfo;
20
21
import com.reallifedeveloper.common.application.notification.NotificationLog;
22
import com.reallifedeveloper.common.application.notification.NotificationLogId;
23
import com.reallifedeveloper.common.application.notification.NotificationService;
24
import com.reallifedeveloper.common.domain.ObjectSerializer;
25
import com.reallifedeveloper.common.resource.BaseResource;
26
import com.reallifedeveloper.common.resource.ResourceUtil;
27
28
/**
29
 * A JAX-RS resource to give access to {@link com.reallifedeveloper.common.application.notification.Notification Notifications} in the form
30
 * of a {@link NotificationLog}.
31
 *
32
 * @author RealLifeDeveloper
33
 */
34
@Path("/notifications")
35
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
36
@SuppressWarnings("PMD.AvoidCatchingGenericException")
37
@SuppressFBWarnings(value = "JAXRS_ENDPOINT", justification = "Please ensure the JAX-RS REST endpoints here are used in a secure way")
38
public final class NotificationResource extends BaseResource {
39
40
    /**
41
     * The maximum number of notifications returned by {@link #getCurrentNotificationLog(UriInfo)}.
42
     */
43
    public static final int BATCH_SIZE = 20;
44
45
    private static final int CACHE_1_MINUTE = 60;
46
    private static final int CACHE_1_HOUR = 60 * 60;
47
48
    private final NotificationService notificationService;
49
50
    private final ObjectSerializer<String> objectSerializer;
51
52
    /**
53
     * Creates a new {@code NotificationResource} using the given {@link NotificationService} and {@link ObjectSerializer}.
54
     *
55
     * @param notificationService the {@code NotificationService} to use
56
     * @param objectSerializer    the {@code ObjectSerializer} to use
57
     */
58
    public NotificationResource(NotificationService notificationService, ObjectSerializer<String> objectSerializer) {
59 2 1. <init> : negated conditional → KILLED
2. <init> : negated conditional → KILLED
        if (notificationService == null || objectSerializer == null) {
60
            throw new IllegalArgumentException(
61
                    "Arguments must not be null: notificationService=" + notificationService + ", objectSerializer=" + objectSerializer);
62
        }
63
        this.notificationService = notificationService;
64
        this.objectSerializer = objectSerializer;
65
    }
66
67
    /**
68
     * Gives the most recent notifications.
69
     *
70
     * @param uriInfo provides access to application and request URI information, injected by JAX-RS
71
     *
72
     * @return a {@code Response} containing a {@link NotificationLogRepresentation}
73
     */
74
    @GET
75
    public Response getCurrentNotificationLog(@Context UriInfo uriInfo) {
76
        try {
77
            logger().debug("getCurrentNotificationLog");
78
            NotificationLog currentNotificationLog = notificationService.currentNotificationLog(BATCH_SIZE);
79
            Links links = new Links(currentNotificationLog, uriInfo);
80
            NotificationLogRepresentation representation = buildRepresentation(currentNotificationLog, links);
81 1 1. getCurrentNotificationLog : replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::getCurrentNotificationLog → KILLED
            return Response.ok(representation).links(links.allLinks).cacheControl(ResourceUtil.cacheControl(CACHE_1_MINUTE)).build();
82
        } catch (Exception e) {
83
            throw handleError("getCurrentNotificationLog", e);
84
        }
85
    }
86
87
    /**
88
     * Gives a specific set of notifications.
89
     * <p>
90
     * The notifications are identified by their stored event IDs. As an argument, you provide the ID of the first and the last notification
91
     * you are interested in, in the form "&lt;low&gt;,&lt;high&gt;" where &lt;low&gt; is the ID of the first notification, and &lt;high&gt;
92
     * is the ID of the last notification.
93
     * <p>
94
     * For example, given the string "89661,89680", this method will return the notifications with IDs between 89661 and 89680, inclusive,
95
     * if available.
96
     *
97
     * @param notificationLogIdString a string on the form "&lt;low&gt;,&lt;high&gt;"
98
     * @param uriInfo                 provides access to application and request URI information, injected by JAX-RS
99
     *
100
     * @return a {@code Response} containing a {@link NotificationLogRepresentation}
101
     */
102
    @GET
103
    @Path("{notificationLogId}")
104
    public Response getNotificationLog(@PathParam("notificationLogId") String notificationLogIdString, @Context UriInfo uriInfo) {
105
        try {
106
            logger().debug("getNotificationLog: notificationLogIdString={}", removeCRLF(notificationLogIdString));
107
            NotificationLogId notificationLogId = new NotificationLogId(notificationLogIdString);
108
            NotificationLog notificationLog = notificationService.notificationLog(notificationLogId);
109
            Links links = new Links(notificationLog, uriInfo);
110
            NotificationLogRepresentation representation = buildRepresentation(notificationLog, links);
111 1 1. getNotificationLog : replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::getNotificationLog → KILLED
            return Response.ok(representation).links(links.allLinks).cacheControl(ResourceUtil.cacheControl(CACHE_1_HOUR)).build();
112
        } catch (Exception e) {
113
            throw handleError("getNotificationLog", e);
114
        }
115
    }
116
117
    private NotificationLogRepresentation buildRepresentation(NotificationLog notificationLog, Links links) {
118
        NotificationLogRepresentation representation = new NotificationLogRepresentation(notificationLog, objectSerializer);
119 1 1. buildRepresentation : removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setSelf → SURVIVED
        representation.setSelf(links.self.getUri().toString());
120 1 1. buildRepresentation : negated conditional → KILLED
        if (links.next.isPresent()) {
121 1 1. buildRepresentation : removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setNext → SURVIVED
            representation.setNext(links.next.get().getUri().toString());
122
        }
123 1 1. buildRepresentation : negated conditional → KILLED
        if (links.previous.isPresent()) {
124 1 1. buildRepresentation : removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setPrevious → SURVIVED
            representation.setPrevious(links.previous.get().getUri().toString());
125
        }
126 1 1. buildRepresentation : replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::buildRepresentation → KILLED
        return representation;
127
    }
128
129
    private static class Links {
130
131
        private final Link self;
132
        private final Optional<Link> next;
133
        private final Optional<Link> previous;
134
        private final Link[] allLinks;
135
136
        /* package-private */ Links(NotificationLog notificationLog, UriInfo uriInfo) {
137
            UriBuilder uriBuilder = uriInfo.getBaseUriBuilder().path(NotificationResource.class).path(NotificationResource.class,
138
                    "getNotificationLog");
139
            List<Link> linkList = new ArrayList<>();
140
141
            this.self = Link.fromUriBuilder(uriBuilder).rel("self").build(notificationLog.current().externalForm());
142
            linkList.add(this.self);
143
144 1 1. lambda$new$0 : replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource$Links::lambda$new$0 → KILLED
            this.next = notificationLog.next().map(link -> Link.fromUriBuilder(uriBuilder).rel("next").build(link.externalForm()));
145 1 1. <init> : removed call to java/util/Optional::ifPresent → KILLED
            this.next.ifPresent(linkList::add);
146
147
            this.previous = notificationLog.previous()
148 1 1. lambda$new$1 : replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource$Links::lambda$new$1 → KILLED
                    .map(link -> Link.fromUriBuilder(uriBuilder).rel("previous").build(link.externalForm()));
149 1 1. <init> : removed call to java/util/Optional::ifPresent → KILLED
            this.previous.ifPresent(linkList::add);
150
151
            this.allLinks = new Link[linkList.size()];
152
            linkList.toArray(this.allLinks);
153
        }
154
    }
155
}

Mutations

59

1.1
Location : <init>
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:constructorNullObjectSerializer()]
negated conditional → KILLED

2.2
Location : <init>
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:constructorNullObjectSerializer()]
negated conditional → KILLED

81

1.1
Location : getCurrentNotificationLog
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogNoNotifications()]
replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::getCurrentNotificationLog → KILLED

111

1.1
Location : getNotificationLog
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getNotificationLog()]
replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::getNotificationLog → KILLED

119

1.1
Location : buildRepresentation
Killed by : none
removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setSelf → SURVIVED
Covering tests

120

1.1
Location : buildRepresentation
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogNoNotifications()]
negated conditional → KILLED

121

1.1
Location : buildRepresentation
Killed by : none
removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setNext → SURVIVED
Covering tests

123

1.1
Location : buildRepresentation
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogNoNotifications()]
negated conditional → KILLED

124

1.1
Location : buildRepresentation
Killed by : none
removed call to com/reallifedeveloper/common/resource/notification/NotificationLogRepresentation::setPrevious → SURVIVED
Covering tests

126

1.1
Location : buildRepresentation
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogNoNotifications()]
replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource::buildRepresentation → KILLED

144

1.1
Location : lambda$new$0
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getNotificationLog()]
replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource$Links::lambda$new$0 → KILLED

145

1.1
Location : <init>
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getNotificationLog()]
removed call to java/util/Optional::ifPresent → KILLED

148

1.1
Location : lambda$new$1
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogFullBatchPlusOne()]
replaced return value with null for com/reallifedeveloper/common/resource/notification/NotificationResource$Links::lambda$new$1 → KILLED

149

1.1
Location : <init>
Killed by : com.reallifedeveloper.common.resource.notification.NotificationResourceTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.resource.notification.NotificationResourceTest]/[method:getCurrentNotificationLogFullBatchPlusOne()]
removed call to java/util/Optional::ifPresent → KILLED

Active mutators

Tests examined


Report generated by PIT 1.20.0