22
22
import static com .google .common .net .HttpHeaders .CONTENT_TYPE ;
23
23
import static com .google .common .net .MediaType .JSON_UTF_8 ;
24
24
import static org .openqa .selenium .json .Json .MAP_TYPE ;
25
- import static org .openqa .selenium .remote .BrowserType .CHROME ;
26
- import static org .openqa .selenium .remote .BrowserType .EDGE ;
27
- import static org .openqa .selenium .remote .BrowserType .FIREFOX ;
28
- import static org .openqa .selenium .remote .BrowserType .IE ;
29
- import static org .openqa .selenium .remote .BrowserType .OPERA ;
30
- import static org .openqa .selenium .remote .BrowserType .OPERA_BLINK ;
31
- import static org .openqa .selenium .remote .BrowserType .SAFARI ;
32
25
import static org .openqa .selenium .remote .CapabilityType .PROXY ;
33
26
34
27
import com .google .common .base .Preconditions ;
46
39
import org .openqa .selenium .remote .http .HttpMethod ;
47
40
import org .openqa .selenium .remote .http .HttpRequest ;
48
41
import org .openqa .selenium .remote .http .HttpResponse ;
42
+ import org .openqa .selenium .remote .session .CapabilitiesFilter ;
43
+ import org .openqa .selenium .remote .session .ChromeFilter ;
44
+ import org .openqa .selenium .remote .session .EdgeFilter ;
45
+ import org .openqa .selenium .remote .session .FirefoxFilter ;
46
+ import org .openqa .selenium .remote .session .InternetExplorerFilter ;
47
+ import org .openqa .selenium .remote .session .OperaFilter ;
48
+ import org .openqa .selenium .remote .session .SafariFilter ;
49
49
50
50
import java .io .BufferedInputStream ;
51
51
import java .io .BufferedWriter ;
56
56
import java .util .Collection ;
57
57
import java .util .List ;
58
58
import java .util .Map ;
59
+ import java .util .Objects ;
59
60
import java .util .Optional ;
61
+ import java .util .ServiceLoader ;
60
62
import java .util .Set ;
61
63
import java .util .TreeMap ;
62
64
import java .util .function .Function ;
@@ -89,12 +91,31 @@ public class ProtocolHandshake {
89
91
.map (Pattern ::asPredicate )
90
92
.reduce (identity -> false , Predicate ::or );
91
93
94
+ private final Set <CapabilitiesFilter > adapters ;
95
+
96
+ public ProtocolHandshake () {
97
+ ImmutableSet .Builder <CapabilitiesFilter > builder = ImmutableSet .builder ();
98
+
99
+ ServiceLoader <CapabilitiesFilter > loader = ServiceLoader .load (CapabilitiesFilter .class );
100
+ loader .forEach (builder ::add );
101
+
102
+ builder
103
+ .add (new ChromeFilter ())
104
+ .add (new EdgeFilter ())
105
+ .add (new FirefoxFilter ())
106
+ .add (new InternetExplorerFilter ())
107
+ .add (new OperaFilter ())
108
+ .add (new SafariFilter ());
109
+
110
+ this .adapters = builder .build ();
111
+ }
112
+
92
113
public Result createSession (HttpClient client , Command command )
93
114
throws IOException {
94
115
Capabilities desired = (Capabilities ) command .getParameters ().get ("desiredCapabilities" );
95
116
desired = desired == null ? new ImmutableCapabilities () : desired ;
96
117
97
- Map <String , ? > des = desired .asMap ();
118
+ @ SuppressWarnings ( "unchecked" ) Map <String , Object > des = ( Map < String , Object >) desired .asMap ();
98
119
99
120
// We don't know how large the generated JSON is going to be. Spool it to disk, and then read
100
121
// the file size, then stream it to the remote end. If we could be sure the remote end could
@@ -142,14 +163,14 @@ public Result createSession(HttpClient client, Command command)
142
163
143
164
private void streamJsonWireProtocolParameters (
144
165
JsonOutput out ,
145
- Map <String , ? > des ) throws IOException {
166
+ Map <String , Object > des ) throws IOException {
146
167
out .name ("desiredCapabilities" );
147
168
out .write (des , MAP_TYPE );
148
169
}
149
170
150
171
private void streamW3CProtocolParameters (
151
172
JsonOutput out ,
152
- Map <String , ? > des ) throws IOException {
173
+ Map <String , Object > des ) throws IOException {
153
174
// Technically we should be building up a combination of "alwaysMatch" and "firstMatch" options.
154
175
// We're going to do a little processing to figure out what we might be able to do, and assume
155
176
// that people don't really understand the difference between required and desired (which is
@@ -170,61 +191,12 @@ private void streamW3CProtocolParameters(
170
191
// We can't use the constants defined in the classes because it would introduce circular
171
192
// dependencies between the remote library and the implementations. Yay!
172
193
173
- Map <String , ?> chrome = des .entrySet ().stream ()
174
- .filter (entry ->
175
- ("browserName" .equals (entry .getKey ()) && CHROME .equals (entry .getValue ())) ||
176
- "chromeOptions" .equals (entry .getKey ()))
177
- .distinct ()
178
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
179
-
180
- Map <String , ?> edge = des .entrySet ().stream ()
181
- .filter (entry -> ("browserName" .equals (entry .getKey ()) && EDGE .equals (entry .getValue ())))
182
- .distinct ()
183
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
184
-
185
- Map <String , ?> firefox = des .entrySet ().stream ()
186
- .filter (entry ->
187
- ("browserName" .equals (entry .getKey ()) && FIREFOX .equals (entry .getValue ())) ||
188
- entry .getKey ().startsWith ("firefox_" ) ||
189
- entry .getKey ().startsWith ("moz:" ))
190
- .distinct ()
191
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
192
-
193
- Map <String , ?> ie = des .entrySet ().stream ()
194
- .filter (entry ->
195
- ("browserName" .equals (entry .getKey ()) && IE .equals (entry .getValue ())) ||
196
- "browserAttachTimeout" .equals (entry .getKey ()) ||
197
- "enableElementCacheCleanup" .equals (entry .getKey ()) ||
198
- "enablePersistentHover" .equals (entry .getKey ()) ||
199
- "extractPath" .equals (entry .getKey ()) ||
200
- "host" .equals (entry .getKey ()) ||
201
- "ignoreZoomSetting" .equals (entry .getKey ()) ||
202
- "initialBrowserZoom" .equals (entry .getKey ()) ||
203
- "logFile" .equals (entry .getKey ()) ||
204
- "logLevel" .equals (entry .getKey ()) ||
205
- "requireWindowFocus" .equals (entry .getKey ()) ||
206
- "se:ieOptions" .equals (entry .getKey ()) ||
207
- "silent" .equals (entry .getKey ()) ||
208
- entry .getKey ().startsWith ("ie." ))
209
- .distinct ()
210
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
211
-
212
- Map <String , ?> opera = des .entrySet ().stream ()
213
- .filter (entry ->
214
- ("browserName" .equals (entry .getKey ()) && OPERA_BLINK .equals (entry .getValue ())) ||
215
- ("browserName" .equals (entry .getKey ()) && OPERA .equals (entry .getValue ())) ||
216
- "operaOptions" .equals (entry .getKey ()))
217
- .distinct ()
218
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
219
-
220
- Map <String , ?> safari = des .entrySet ().stream ()
221
- .filter (entry ->
222
- ("browserName" .equals (entry .getKey ()) && SAFARI .equals (entry .getValue ())) ||
223
- "safari.options" .equals (entry .getKey ()))
224
- .distinct ()
225
- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (left , right ) -> right ));
194
+ ImmutableSet <Map <String , Object >> browserSpecific = adapters .stream ()
195
+ .map (adapter -> adapter .apply (des ))
196
+ .filter (Objects ::nonNull )
197
+ .collect (ImmutableSet .toImmutableSet ());
226
198
227
- Set <String > excludedKeys = Stream . of ( chrome , edge , firefox , ie , opera , safari )
199
+ Set <String > excludedKeys = browserSpecific . stream ( )
228
200
.map (Map ::keySet )
229
201
.flatMap (Collection ::stream )
230
202
.distinct ()
@@ -249,7 +221,7 @@ private void streamW3CProtocolParameters(
249
221
}));
250
222
251
223
// Now, hopefully we're left with just the browser-specific pieces. Skip the empty ones.
252
- List <Map <String , Object >> firstMatch = Stream . of ( chrome , edge , firefox , ie , opera , safari )
224
+ List <Map <String , Object >> firstMatch = browserSpecific . stream ( )
253
225
.map (map -> {
254
226
TreeMap <String , Object > json = new TreeMap <>();
255
227
for (Map .Entry <String , ?> entry : map .entrySet ()) {
@@ -328,7 +300,7 @@ public Optional<Result> createSession(HttpClient client, InputStream newSessionB
328
300
329
301
private void streamGeckoDriver013Parameters (
330
302
JsonOutput out ,
331
- Map <String , ? > des ) throws IOException {
303
+ Map <String , Object > des ) throws IOException {
332
304
out .name ("desiredCapabilities" );
333
305
out .write (des , MAP_TYPE );
334
306
}
0 commit comments