Skip to content

Commit bfd5c1e

Browse files
committed
Extract some of the functionality of the CommandHandlerServlet
1 parent 40a8a12 commit bfd5c1e

5 files changed

Lines changed: 147 additions & 58 deletions

File tree

java/server/src/org/openqa/selenium/grid/server/BaseServer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ public BaseServer(BaseServerOptions options) {
145145

146146
server.setConnectors(new Connector[]{http});
147147

148-
addServlet(new CommandHandlerServlet(injector, handlers), "/*");
148+
CommandHandler delegate = new CompoundHandler(injector, handlers);
149+
W3CCommandHandler handler = new W3CCommandHandler(delegate);
150+
addServlet(new CommandHandlerServlet(handler), "/*");
149151
}
150152

151153
@Override

java/server/src/org/openqa/selenium/grid/server/CommandHandlerServlet.java

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,23 @@
1717

1818
package org.openqa.selenium.grid.server;
1919

20-
import static com.google.common.net.MediaType.JSON_UTF_8;
21-
import static java.nio.charset.StandardCharsets.UTF_8;
22-
23-
import com.google.common.collect.ImmutableMap;
24-
25-
import org.openqa.selenium.UnsupportedCommandException;
2620
import org.openqa.selenium.grid.web.CommandHandler;
27-
import org.openqa.selenium.injector.Injector;
28-
import org.openqa.selenium.json.Json;
29-
import org.openqa.selenium.remote.ErrorCodes;
3021
import org.openqa.selenium.remote.http.HttpRequest;
3122
import org.openqa.selenium.remote.http.HttpResponse;
3223

3324
import java.io.IOException;
34-
import java.util.Map;
3525
import java.util.Objects;
36-
import java.util.function.BiFunction;
37-
import java.util.function.Predicate;
3826

3927
import javax.servlet.http.HttpServlet;
4028
import javax.servlet.http.HttpServletRequest;
4129
import javax.servlet.http.HttpServletResponse;
4230

4331
class CommandHandlerServlet extends HttpServlet {
4432

45-
private final static Json JSON = new Json();
46-
private final Map<Predicate<HttpRequest>, BiFunction<Injector, HttpRequest, CommandHandler>>
47-
handlers;
48-
private final Injector injector;
49-
private final ErrorCodes errors = new ErrorCodes();
33+
private final CommandHandler handler;
5034

51-
public CommandHandlerServlet(
52-
Injector injector,
53-
Map<Predicate<HttpRequest>, BiFunction<Injector, HttpRequest, CommandHandler>> handlers) {
54-
this.injector = Objects.requireNonNull(injector);
55-
this.handlers = Objects.requireNonNull(handlers);
35+
public CommandHandlerServlet(CommandHandler handler) {
36+
this.handler = Objects.requireNonNull(handler);
5637
}
5738

5839
@Override
@@ -61,29 +42,6 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws
6142
HttpRequest request = new ServletRequestWrappingHttpRequest(req);
6243
HttpResponse response = new ServletResponseWrappingHttpResponse(resp);
6344

64-
BiFunction<Injector, HttpRequest, CommandHandler> generator = handlers.entrySet().stream()
65-
.filter(entry -> entry.getKey().test(request))
66-
.map(Map.Entry::getValue)
67-
.findFirst()
68-
.orElse((inj, ignored) -> (in, out) -> {
69-
throw new UnsupportedCommandException(
70-
String.format("Unable to find command matching (%s) %s",
71-
request.getMethod(),
72-
request.getUri()));
73-
});
74-
75-
try {
76-
generator.apply(injector, request).execute(request, response);
77-
} catch (Throwable e) {
78-
// Fair enough. Attempt to convert the exception to something useful.
79-
response.setStatus(errors.getHttpStatusCode(e));
80-
81-
response.setHeader("Content-Type", JSON_UTF_8.toString());
82-
response.setHeader("Cache-Control", "none");
83-
84-
response.setContent(
85-
JSON.toJson(ImmutableMap.of("status", errors.toStatusCode(e), "value", e))
86-
.getBytes(UTF_8));
87-
}
45+
handler.execute(request, response);
8846
}
8947
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.server;
19+
20+
import org.openqa.selenium.UnsupportedCommandException;
21+
import org.openqa.selenium.grid.web.CommandHandler;
22+
import org.openqa.selenium.injector.Injector;
23+
import org.openqa.selenium.remote.http.HttpRequest;
24+
import org.openqa.selenium.remote.http.HttpResponse;
25+
26+
import java.io.IOException;
27+
import java.util.Map;
28+
import java.util.Objects;
29+
import java.util.function.BiFunction;
30+
import java.util.function.Predicate;
31+
32+
public class CompoundHandler implements Predicate<HttpRequest>, CommandHandler {
33+
34+
private final Injector injector;
35+
private final Map<Predicate<HttpRequest>, BiFunction<Injector, HttpRequest, CommandHandler>>
36+
handlers;
37+
38+
public CompoundHandler(
39+
Injector injector,
40+
Map<Predicate<HttpRequest>, BiFunction<Injector, HttpRequest, CommandHandler>> handlers) {
41+
42+
this.injector = Objects.requireNonNull(injector);
43+
this.handlers = Objects.requireNonNull(handlers);
44+
}
45+
46+
@Override
47+
public boolean test(HttpRequest request) {
48+
return handlers.keySet().parallelStream().anyMatch(pred -> pred.test(request));
49+
}
50+
51+
@Override
52+
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
53+
BiFunction<Injector, HttpRequest, CommandHandler> generator =
54+
handlers.entrySet().stream()
55+
.filter(entry -> entry.getKey().test(req))
56+
.map(Map.Entry::getValue)
57+
.findFirst()
58+
.orElseThrow(() -> new UnsupportedCommandException(String.format(
59+
"Unknown command: (%s) %s", req.getMethod(), req.getUri())));
60+
61+
CommandHandler handler = generator.apply(injector, req);
62+
handler.execute(req, resp);
63+
}
64+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.server;
19+
20+
import static com.google.common.net.MediaType.JSON_UTF_8;
21+
import static java.nio.charset.StandardCharsets.UTF_8;
22+
23+
import com.google.common.collect.ImmutableMap;
24+
25+
import org.openqa.selenium.grid.web.CommandHandler;
26+
import org.openqa.selenium.json.Json;
27+
import org.openqa.selenium.remote.ErrorCodes;
28+
import org.openqa.selenium.remote.http.HttpRequest;
29+
import org.openqa.selenium.remote.http.HttpResponse;
30+
31+
import java.io.IOException;
32+
import java.util.Objects;
33+
34+
public class W3CCommandHandler implements CommandHandler {
35+
36+
public static final Json JSON = new Json();
37+
private final ErrorCodes errors = new ErrorCodes();
38+
private final CommandHandler delegate;
39+
40+
public W3CCommandHandler(CommandHandler delegate) {
41+
this.delegate = Objects.requireNonNull(delegate);
42+
}
43+
44+
@Override
45+
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
46+
// Assume we're executing a normal W3C WebDriver request
47+
resp.setHeader("Content-Type", JSON_UTF_8.toString());
48+
resp.setHeader("Cache-Control", "none");
49+
50+
try {
51+
delegate.execute(req, resp);
52+
} catch (Throwable cause) {
53+
// Fair enough. Attempt to convert the exception to something useful.
54+
resp.setStatus(errors.getHttpStatusCode(cause));
55+
56+
resp.setHeader("Content-Type", JSON_UTF_8.toString());
57+
resp.setHeader("Cache-Control", "none");
58+
59+
resp.setContent(JSON.toJson(
60+
ImmutableMap.of(
61+
"status", errors.toStatusCode(cause),
62+
"value", cause)).getBytes(UTF_8));
63+
}
64+
}
65+
}

java/server/test/org/openqa/selenium/grid/server/CommandHandlerServletTest.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,7 @@ public void shouldReturnValueFromHandlerIfUrlMatches() throws IOException {
7575
Injector injector = Injector.builder().register(new Json()).build();
7676

7777
CommandHandlerServlet servlet = new CommandHandlerServlet(
78-
injector,
79-
ImmutableMap.of(
80-
(req) -> true, (inj, ingored) ->
81-
(req, res) -> res.setContent(cheerfulGreeting.getBytes(UTF_8))));
78+
(req, res) -> res.setContent(cheerfulGreeting.getBytes(UTF_8)));
8279

8380
HttpServletRequest request = requestConverter.apply(new HttpRequest(GET, "/hello-world"));
8481
FakeHttpServletResponse response = new FakeHttpServletResponse();
@@ -93,7 +90,8 @@ public void shouldReturnValueFromHandlerIfUrlMatches() throws IOException {
9390
public void shouldCorrectlyReturnAnUnknownCommandExceptionForUnmappableUrls() throws IOException {
9491
Injector injector = Injector.builder().register(new Json()).build();
9592

96-
CommandHandlerServlet servlet = new CommandHandlerServlet(injector, ImmutableMap.of());
93+
CommandHandlerServlet servlet = new CommandHandlerServlet(
94+
new W3CCommandHandler(new CompoundHandler(injector, ImmutableMap.of())));
9795

9896
HttpServletRequest request = requestConverter.apply(new HttpRequest(GET, "/missing"));
9997
FakeHttpServletResponse response = new FakeHttpServletResponse();
@@ -109,12 +107,14 @@ public void exceptionsThrownByHandlersAreConvertedToAProperPayload() throws IOEx
109107
Injector injector = Injector.builder().register(new Json()).build();
110108

111109
CommandHandlerServlet servlet = new CommandHandlerServlet(
112-
injector,
113-
ImmutableMap.of(
114-
req -> true,
115-
(inj, ignored) -> (req, res) -> {
116-
throw new UnableToSetCookieException("Yowza");
117-
}));
110+
new W3CCommandHandler(
111+
new CompoundHandler(
112+
injector,
113+
ImmutableMap.of(
114+
req -> true,
115+
(inj, ignored) -> (req, res) -> {
116+
throw new UnableToSetCookieException("Yowza");
117+
}))));
118118

119119
HttpServletRequest request = requestConverter.apply(new HttpRequest(GET, "/exceptional"));
120120
FakeHttpServletResponse response = new FakeHttpServletResponse();

0 commit comments

Comments
 (0)