Skip to content

Commit ba07615

Browse files
committed
Make it easier to subclass a remote ActiveSession
1 parent 5385e40 commit ba07615

File tree

3 files changed

+228
-156
lines changed

3 files changed

+228
-156
lines changed

java/server/src/org/openqa/selenium/remote/server/BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ java_library(
7878
'NewSessionPipeline.java',
7979
'Passthrough.java',
8080
'ProtocolConverter.java',
81+
'RemoteSession.java',
8182
'ServicedSession.java',
8283
'SessionCodec.java',
8384
'SessionFactory.java',
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package org.openqa.selenium.remote.server;
2+
3+
import static org.openqa.selenium.remote.Dialect.OSS;
4+
5+
import com.google.common.base.Preconditions;
6+
import com.google.common.base.StandardSystemProperty;
7+
import com.google.common.collect.ImmutableMap;
8+
9+
import org.openqa.selenium.Capabilities;
10+
import org.openqa.selenium.ImmutableCapabilities;
11+
import org.openqa.selenium.WebDriver;
12+
import org.openqa.selenium.io.TemporaryFilesystem;
13+
import org.openqa.selenium.remote.Augmenter;
14+
import org.openqa.selenium.remote.Command;
15+
import org.openqa.selenium.remote.CommandCodec;
16+
import org.openqa.selenium.remote.CommandExecutor;
17+
import org.openqa.selenium.remote.Dialect;
18+
import org.openqa.selenium.remote.DriverCommand;
19+
import org.openqa.selenium.remote.ProtocolHandshake;
20+
import org.openqa.selenium.remote.RemoteWebDriver;
21+
import org.openqa.selenium.remote.Response;
22+
import org.openqa.selenium.remote.ResponseCodec;
23+
import org.openqa.selenium.remote.SessionId;
24+
import org.openqa.selenium.remote.http.HttpClient;
25+
import org.openqa.selenium.remote.http.HttpRequest;
26+
import org.openqa.selenium.remote.http.HttpResponse;
27+
import org.openqa.selenium.remote.http.JsonHttpCommandCodec;
28+
import org.openqa.selenium.remote.http.JsonHttpResponseCodec;
29+
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
30+
import org.openqa.selenium.remote.http.W3CHttpResponseCodec;
31+
import org.openqa.selenium.remote.internal.ApacheHttpClient;
32+
33+
import java.io.File;
34+
import java.io.IOException;
35+
import java.net.URL;
36+
import java.util.Map;
37+
import java.util.Optional;
38+
import java.util.Set;
39+
import java.util.logging.Level;
40+
import java.util.logging.Logger;
41+
42+
/**
43+
* Abstract class designed to do things like protocol conversion.
44+
*/
45+
public abstract class RemoteSession implements ActiveSession {
46+
47+
protected static Logger log = Logger.getLogger(ActiveSession.class.getName());
48+
49+
private final SessionId id;
50+
private final Dialect downstream;
51+
private final Dialect upstream;
52+
private final SessionCodec codec;
53+
private final Map<String, Object> capabilities;
54+
private final TemporaryFilesystem filesystem;
55+
private final WebDriver driver;
56+
57+
protected RemoteSession(
58+
Dialect downstream,
59+
Dialect upstream,
60+
SessionCodec codec,
61+
SessionId id,
62+
Map<String, Object> capabilities) {
63+
this.downstream = downstream;
64+
this.upstream = upstream;
65+
this.codec = codec;
66+
this.id = id;
67+
this.capabilities = capabilities;
68+
69+
File tempRoot = new File(StandardSystemProperty.JAVA_IO_TMPDIR.value(), id.toString());
70+
Preconditions.checkState(tempRoot.mkdirs());
71+
this.filesystem = TemporaryFilesystem.getTmpFsBasedOn(tempRoot);
72+
73+
CommandExecutor executor = new ActiveSessionCommandExecutor(this);
74+
this.driver = new Augmenter().augment(new RemoteWebDriver(
75+
executor,
76+
new ImmutableCapabilities(getCapabilities())));
77+
}
78+
79+
@Override
80+
public SessionId getId() {
81+
return id;
82+
}
83+
84+
@Override
85+
public Dialect getUpstreamDialect() {
86+
return upstream;
87+
}
88+
89+
@Override
90+
public Dialect getDownstreamDialect() {
91+
return downstream;
92+
}
93+
94+
@Override
95+
public Map<String, Object> getCapabilities() {
96+
return capabilities;
97+
}
98+
99+
@Override
100+
public TemporaryFilesystem getFileSystem() {
101+
return filesystem;
102+
}
103+
104+
@Override
105+
public WebDriver getWrappedDriver() {
106+
return driver;
107+
}
108+
109+
@Override
110+
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
111+
codec.handle(req, resp);
112+
}
113+
114+
public abstract static class Factory<X> implements SessionFactory {
115+
116+
protected Optional<ActiveSession> performHandshake(
117+
X additionalData,
118+
URL url,
119+
Set<Dialect> downstreamDialects,
120+
Capabilities capabilities) {
121+
try {
122+
HttpClient client = new ApacheHttpClient.Factory().createClient(url);
123+
124+
Command command = new Command(
125+
null,
126+
DriverCommand.NEW_SESSION,
127+
ImmutableMap.of("desiredCapabilities", capabilities));
128+
129+
ProtocolHandshake.Result result = new ProtocolHandshake().createSession(client, command);
130+
131+
SessionCodec codec;
132+
Dialect upstream = result.getDialect();
133+
Dialect downstream;
134+
if (downstreamDialects.contains(result.getDialect())) {
135+
codec = new Passthrough(url);
136+
downstream = upstream;
137+
} else {
138+
downstream = downstreamDialects.isEmpty() ? OSS : downstreamDialects.iterator().next();
139+
140+
codec = new ProtocolConverter(
141+
url,
142+
getCommandCodec(downstream),
143+
getResponseCodec(downstream),
144+
getCommandCodec(upstream),
145+
getResponseCodec(upstream));
146+
}
147+
148+
Response response = result.createResponse();
149+
//noinspection unchecked
150+
return Optional.of(newActiveSession(
151+
additionalData,
152+
downstream,
153+
upstream,
154+
codec,
155+
new SessionId(response.getSessionId()),
156+
(Map<String, Object>) response.getValue()));
157+
} catch (IOException | IllegalStateException | NullPointerException e) {
158+
log.log(Level.WARNING, e.getMessage(), e);
159+
return Optional.empty();
160+
}
161+
}
162+
163+
protected abstract ActiveSession newActiveSession(
164+
X additionalData,
165+
Dialect downstream,
166+
Dialect upstream,
167+
SessionCodec codec,
168+
SessionId id,
169+
Map<String, Object> capabilities);
170+
171+
private CommandCodec<HttpRequest> getCommandCodec(Dialect dialect) {
172+
switch (dialect) {
173+
case OSS:
174+
return new JsonHttpCommandCodec();
175+
176+
case W3C:
177+
return new W3CHttpCommandCodec();
178+
179+
default:
180+
throw new IllegalStateException("Unknown dialect: " + dialect);
181+
}
182+
}
183+
184+
private ResponseCodec<HttpResponse> getResponseCodec(Dialect dialect) {
185+
switch (dialect) {
186+
case OSS:
187+
return new JsonHttpResponseCodec();
188+
189+
case W3C:
190+
return new W3CHttpResponseCodec();
191+
192+
default:
193+
throw new IllegalStateException("Unknown dialect: " + dialect);
194+
}
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)