Skip to content

Commit e93212c

Browse files
committed
Address issues in PR and remove static state
1 parent 97e2f77 commit e93212c

20 files changed

+160
-96
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package edu.wpi.grip.core.http;
2+
3+
import com.google.inject.Singleton;
4+
5+
import javax.annotation.Nullable;
6+
import java.util.HashSet;
7+
import java.util.Set;
8+
9+
import static com.google.common.base.Preconditions.checkNotNull;
10+
11+
/**
12+
* Keeps a record of contexts claimed by HTTP request handlers.
13+
*/
14+
@Singleton
15+
public class ContextStore {
16+
17+
private final Set<String> store = new HashSet<>();
18+
19+
/**
20+
* Records the given context.
21+
*
22+
* @param context the context to record. This cannot be null.
23+
* @throws IllegalArgumentException if the given context has already been claimed
24+
*/
25+
public void record(String context) throws IllegalArgumentException {
26+
checkNotNull(context);
27+
if (!store.add(context)) {
28+
throw new IllegalArgumentException("Context is already claimed: " + context);
29+
}
30+
}
31+
32+
/**
33+
* Erases the given context from this store, if it's present. If {@code context} is {@code null}, this will
34+
* do nothing and return {@code false}.
35+
*
36+
* @param context the context to erase
37+
* @return true if the context was erased, false if it wasn't erased or if it wasn't present to begin with.
38+
*/
39+
public boolean erase(@Nullable String context) {
40+
return store.remove(context);
41+
}
42+
43+
/**
44+
* Checks if the given context has been recorded in this store. If {@code context} is {@code null}, this will
45+
* return {@code false}.
46+
*
47+
* @param context the context to check
48+
* @return true if the given context has been recorded in this store
49+
*/
50+
public boolean contains(@Nullable String context) {
51+
return store.contains(context);
52+
}
53+
54+
55+
}

core/src/main/java/edu/wpi/grip/core/http/GenericHandler.java

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,11 @@
1616
* Generic Jetty handler.
1717
* <p>
1818
* Instances of this class can either claim a context, preventing other instances from handling
19-
* events on that context, or not, in which case it will run on any context. The second type may use
20-
* {@link #isClaimed(String) isClaimed} to check if a context has been claimed if it shouldn't run on a claimed context.
19+
* events on that context, or not, in which case it will run on any context.
2120
*/
2221
public abstract class GenericHandler extends AbstractHandler {
2322

24-
/**
25-
* Claimed contexts.
26-
*/
27-
private static final Set<String> claimedContexts = new HashSet<>();
23+
private final ContextStore contextStore;
2824

2925
/**
3026
* The context that this handles.
@@ -51,6 +47,7 @@ public abstract class GenericHandler extends AbstractHandler {
5147
*/
5248
protected GenericHandler() {
5349
super();
50+
contextStore = new ContextStore();
5451
context = null;
5552
}
5653

@@ -60,11 +57,12 @@ protected GenericHandler() {
6057
* Note that the context <strong>is case sensitive</strong>.
6158
* </p>
6259
*
60+
* @param store the context store to use to check for claimed contexts
6361
* @param context the context for this handler
6462
* @throws IllegalArgumentException if the given context has already been claimed
6563
*/
66-
protected GenericHandler(String context) {
67-
this(context, false);
64+
protected GenericHandler(ContextStore store, String context) {
65+
this(store, context, false);
6866
}
6967

7068
/**
@@ -73,36 +71,26 @@ protected GenericHandler(String context) {
7371
* Note that the context <strong>is case sensitive</strong>.
7472
* </p>
7573
*
74+
* @param store the context store to use to check for claimed contexts
7675
* @param context the context for this handler
7776
* @param doClaim flag marking if the given context should be claimed
7877
* @throws IllegalArgumentException if the given context has already been claimed
7978
*/
80-
protected GenericHandler(String context, boolean doClaim) {
79+
protected GenericHandler(ContextStore store, String context, boolean doClaim) {
8180
super();
8281
checkNotNull(context);
83-
if (isClaimed(context)) {
84-
throw new IllegalArgumentException("The given context has already been claimed: " + context);
85-
}
86-
this.context = context;
8782
if (doClaim) {
88-
claimContext();
83+
store.record(context);
8984
}
90-
}
91-
92-
/**
93-
* Claims the context. Fails if that context has already been claimed and not released.
94-
*
95-
* @return true if the context was claimed, false if it has already been claimed
96-
*/
97-
protected boolean claimContext() {
98-
return claimedContexts.add(context);
85+
this.contextStore = store;
86+
this.context = context;
9987
}
10088

10189
/**
10290
* Releases the context that this handles, allowing it to be claimed by another handler.
10391
*/
10492
protected void releaseContext() {
105-
claimedContexts.remove(context);
93+
contextStore.erase(context);
10694
}
10795

10896
/**
@@ -112,16 +100,6 @@ public String getContext() {
112100
return context;
113101
}
114102

115-
/**
116-
* Checks if the given context has been claimed. Returns {@code false} if given {@code null}.
117-
*
118-
* @param context the context to check
119-
* @return true if the context has been claimed, false if not
120-
*/
121-
protected static boolean isClaimed(@Nullable String context) {
122-
return claimedContexts.contains(context);
123-
}
124-
125103
// Static helper methods
126104

127105
/**

core/src/main/java/edu/wpi/grip/core/http/GripServer.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ public Server create(int port) {
114114
}
115115

116116
@Inject
117-
GripServer(JettyServerFactory serverFactory, SettingsProvider settingsProvider) {
117+
GripServer(ContextStore contextStore, JettyServerFactory serverFactory, SettingsProvider settingsProvider) {
118118
this.port = settingsProvider.getProjectSettings().getServerPort();
119119
this.serverFactory = serverFactory;
120120
this.server = serverFactory.create(port);
121121
this.server.setHandler(handlers);
122-
handlers.addHandler(new NoContextHandler());
122+
handlers.addHandler(new NoContextHandler(contextStore));
123123

124124
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
125125
}
@@ -182,7 +182,14 @@ public void stop() {
182182
*/
183183
public void restart() {
184184
try {
185-
stop();
185+
if (state == State.RUNNING) {
186+
try {
187+
server.stop();
188+
} catch (Exception ex) {
189+
throw new GripServerException("Could not stop Jetty server", ex);
190+
}
191+
state = State.STOPPED;
192+
}
186193
server = serverFactory.create(port);
187194
start();
188195
} catch (GripServerException | IllegalStateException ex) {

core/src/main/java/edu/wpi/grip/core/http/HttpPipelineSwitcher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public class HttpPipelineSwitcher extends PedanticHandler {
2727
private final GRIPMode mode;
2828

2929
@Inject
30-
HttpPipelineSwitcher(Project project, GRIPMode mode) {
31-
super(GripServer.PIPELINE_UPLOAD_PATH, true);
30+
HttpPipelineSwitcher(ContextStore store, Project project, GRIPMode mode) {
31+
super(store, GripServer.PIPELINE_UPLOAD_PATH, true);
3232
this.project = project;
3333
this.mode = mode;
3434
}

core/src/main/java/edu/wpi/grip/core/http/NoContextHandler.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@
1414
*/
1515
class NoContextHandler extends GenericHandler {
1616

17+
private final ContextStore store;
18+
1719
private static final String notFoundMessage = "<h1>404 - Not Found</h1>There is no context for path: '%s'";
1820

19-
// implicit call to super() -- no context is claimed
21+
/**
22+
* Creates a new {@code NoContextHandler} that handles every context not in the given {@code ContextStore}.
23+
*
24+
* @param store Any context not in this {@code ContextStore} will get a {@code 404 Not Found} error.
25+
*/
26+
public NoContextHandler(ContextStore store) {
27+
super();
28+
this.store = store;
29+
}
2030

2131
@Override
2232
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
23-
if (isClaimed(target)) {
33+
if (store.contains(target)) {
2434
// Let the appropriate handler handle this
2535
return;
2636
}

core/src/main/java/edu/wpi/grip/core/http/PedanticHandler.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,24 @@ public abstract class PedanticHandler extends GenericHandler {
2121
/**
2222
* Creates a new handler for the given context. That context will not be claimed.
2323
*
24+
* @param store the {@code ContextStore} to store this context in
2425
* @param context the context for this handler
25-
* @see GenericHandler#GenericHandler(String)
26+
* @see GenericHandler#GenericHandler(ContextStore, String)
2627
*/
27-
protected PedanticHandler(String context) {
28-
super(context);
28+
protected PedanticHandler(ContextStore store, String context) {
29+
super(store, context);
2930
}
3031

3132
/**
3233
* Creates a new handler for the given context.
3334
*
35+
* @param store the {@code ContextStore} to store this context in
3436
* @param context the context for this handler
3537
* @param doClaim if the context should be claimed
36-
* @see GenericHandler#GenericHandler(String, boolean)
38+
* @see GenericHandler#GenericHandler(ContextStore, String, boolean)
3739
*/
38-
protected PedanticHandler(String context, boolean doClaim) {
39-
super(context, doClaim);
40+
protected PedanticHandler(ContextStore store, String context, boolean doClaim) {
41+
super(store, context, doClaim);
4042
}
4143

4244
@Override

core/src/main/java/edu/wpi/grip/core/operations/network/GRIPNetworkModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.inject.AbstractModule;
44
import com.google.inject.name.Names;
55

6+
import edu.wpi.grip.core.http.ContextStore;
67
import edu.wpi.grip.core.http.GripServer;
78
import edu.wpi.grip.core.http.HttpPipelineSwitcher;
89
import edu.wpi.grip.core.operations.network.http.DataHandler;
@@ -26,6 +27,7 @@ protected void configure() {
2627
bind(GripServer.class).asEagerSingleton();
2728
bind(HttpPipelineSwitcher.class).asEagerSingleton();
2829
bind(DataHandler.class).asEagerSingleton();
30+
bind(ContextStore.class).asEagerSingleton();
2931
// Network publishing bindings
3032
bind(MapNetworkPublisherFactory.class)
3133
.annotatedWith(Names.named("ntManager"))

core/src/main/java/edu/wpi/grip/core/operations/network/http/DataHandler.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import com.google.common.eventbus.Subscribe;
44
import com.google.gson.Gson;
55
import com.google.gson.GsonBuilder;
6+
import com.google.inject.Inject;
67
import com.google.inject.Singleton;
78

89
import edu.wpi.grip.core.events.RunStartedEvent;
910
import edu.wpi.grip.core.events.RunStoppedEvent;
11+
import edu.wpi.grip.core.http.ContextStore;
1012
import edu.wpi.grip.core.http.GripServer;
1113
import edu.wpi.grip.core.http.PedanticHandler;
1214

@@ -51,8 +53,9 @@ public final class DataHandler extends PedanticHandler {
5153
*/
5254
private final AtomicBoolean staleData;
5355

54-
DataHandler() {
55-
super(GripServer.DATA_PATH, true);
56+
@Inject
57+
DataHandler(ContextStore store) {
58+
super(store, GripServer.DATA_PATH, true);
5659
this.dataSuppliers = new HashMap<>();
5760
this.gson = new GsonBuilder()
5861
.setPrettyPrinting()

core/src/main/java/edu/wpi/grip/core/sources/HttpImageHandler.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package edu.wpi.grip.core.sources;
22

3+
import edu.wpi.grip.core.http.ContextStore;
34
import edu.wpi.grip.core.http.GripServer;
45
import edu.wpi.grip.core.http.PedanticHandler;
56

@@ -55,17 +56,17 @@ public final class HttpImageHandler extends PedanticHandler {
5556
/**
5657
* Creates an image handler on the default upload path {@code /GRIP/upload/image}
5758
*/
58-
public HttpImageHandler() {
59-
this(GripServer.IMAGE_UPLOAD_PATH);
59+
public HttpImageHandler(ContextStore store) {
60+
this(store, GripServer.IMAGE_UPLOAD_PATH);
6061
}
6162

6263
/**
6364
* Creates an image handler on the given path.
6465
*
6566
* @param path the path on the server that images will be uploaded to
6667
*/
67-
public HttpImageHandler(String path) {
68-
super(path, true);
68+
public HttpImageHandler(ContextStore store, String path) {
69+
super(store, path, true);
6970
callbacks = new ArrayList<>();
7071
}
7172

core/src/main/java/edu/wpi/grip/core/sources/HttpSource.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import edu.wpi.grip.core.Source;
1212
import edu.wpi.grip.core.events.SourceHasPendingUpdateEvent;
1313
import edu.wpi.grip.core.events.SourceRemovedEvent;
14+
import edu.wpi.grip.core.http.ContextStore;
1415
import edu.wpi.grip.core.http.GripServer;
1516
import edu.wpi.grip.core.sockets.OutputSocket;
1617
import edu.wpi.grip.core.sockets.SocketHint;
@@ -66,8 +67,9 @@ public interface Factory {
6667
EventBus eventBus,
6768
OutputSocket.Factory osf,
6869
GripServer server,
70+
ContextStore store,
6971
@Assisted Properties properties) {
70-
this(exceptionWitnessFactory, eventBus, osf, server, properties.getProperty(PATH_PROPERTY));
72+
this(exceptionWitnessFactory, eventBus, osf, server, store, properties.getProperty(PATH_PROPERTY));
7173
}
7274

7375
@AssistedInject
@@ -76,10 +78,11 @@ public interface Factory {
7678
EventBus eventBus,
7779
OutputSocket.Factory osf,
7880
GripServer server,
81+
ContextStore store,
7982
@Assisted String path) {
8083
super(exceptionWitnessFactory);
8184
this.path = path;
82-
this.imageHandler = handlers.computeIfAbsent(path, HttpImageHandler::new);
85+
this.imageHandler = handlers.computeIfAbsent(path, p -> new HttpImageHandler(store, p));
8386
this.imageOutput = osf.create(outputHint);
8487
this.eventBus = eventBus;
8588
// Will add the handler only when the first HttpSource is created -- no-op every subsequent time

0 commit comments

Comments
 (0)