1717package io .appium .java_client .remote ;
1818
1919import static com .google .common .base .Preconditions .checkNotNull ;
20- import static com .google .common .base .Throwables .getRootCause ;
2120import static com .google .common .base .Throwables .throwIfUnchecked ;
22- import static org .openqa .selenium .remote .DriverCommand .GET_ALL_SESSIONS ;
23- import static org .openqa .selenium .remote .DriverCommand .NEW_SESSION ;
24- import static org .openqa .selenium .remote .DriverCommand .QUIT ;
25-
26- import io .appium .java_client .AppiumCommandInfo ;
27- import org .openqa .selenium .NoSuchSessionException ;
28- import org .openqa .selenium .SessionNotCreatedException ;
29- import org .openqa .selenium .UnsupportedCommandException ;
21+ import static java .util .Optional .ofNullable ;
22+
23+ import com .google .common .base .Supplier ;
24+ import com .google .common .base .Throwables ;
25+
3026import org .openqa .selenium .WebDriverException ;
3127import org .openqa .selenium .remote .Command ;
32- import org .openqa .selenium .remote .CommandCodec ;
33- import org .openqa .selenium .remote .CommandExecutor ;
34- import org .openqa .selenium .remote .Dialect ;
28+ import org .openqa .selenium .remote .CommandInfo ;
3529import org .openqa .selenium .remote .DriverCommand ;
36- import org .openqa .selenium .remote .HttpSessionId ;
30+ import org .openqa .selenium .remote .HttpCommandExecutor ;
3731import org .openqa .selenium .remote .Response ;
38- import org .openqa .selenium .remote .ResponseCodec ;
3932import org .openqa .selenium .remote .http .HttpClient ;
40- import org .openqa .selenium .remote .http .HttpRequest ;
41- import org .openqa .selenium .remote .http .HttpResponse ;
4233import org .openqa .selenium .remote .internal .ApacheHttpClient ;
4334import org .openqa .selenium .remote .service .DriverService ;
4435
4536import java .io .IOException ;
4637import java .net .ConnectException ;
4738import java .net .URL ;
4839import java .util .Map ;
40+ import java .util .Optional ;
4941
50- public class AppiumCommandExecutor implements CommandExecutor {
51-
52- private final URL remoteServer ;
53- private final HttpClient client ;
54- private final Map <String , AppiumCommandInfo > additionalCommands ;
55- private CommandCodec <HttpRequest > commandCodec ;
56- private ResponseCodec <HttpResponse > responseCodec ;
57- private DriverService service ;
58-
59- /**
60- * Cretes an instance that sends requests and receives responses.
61- *
62- * @param additionalCommands is the mapped command repository
63- * @param addressOfRemoteServer is the url to connect to the Appium remote/local server
64- * @param httpClientFactory is the http client factory
65- */
66- public AppiumCommandExecutor (Map <String , AppiumCommandInfo > additionalCommands ,
67- URL addressOfRemoteServer , HttpClient .Factory httpClientFactory ) {
68- checkNotNull (addressOfRemoteServer );
69- remoteServer = addressOfRemoteServer ;
70- this .additionalCommands = additionalCommands ;
71- this .client = httpClientFactory .createClient (remoteServer );
72- }
42+ public class AppiumCommandExecutor extends HttpCommandExecutor {
7343
74- public AppiumCommandExecutor (Map <String , AppiumCommandInfo > additionalCommands , DriverService service ,
75- HttpClient .Factory httpClientFactory ) {
76- this (additionalCommands , service .getUrl (), httpClientFactory );
77- this .service = service ;
78- }
44+ private final Optional <DriverService > serviceOptional ;
7945
80- public AppiumCommandExecutor (Map <String , AppiumCommandInfo > additionalCommands ,
81- URL addressOfRemoteServer ) {
82- this (additionalCommands , addressOfRemoteServer , new ApacheHttpClient .Factory ());
46+ private AppiumCommandExecutor (Map <String , CommandInfo > additionalCommands , DriverService service ,
47+ URL addressOfRemoteServer ,
48+ HttpClient .Factory httpClientFactory ) {
49+ super (additionalCommands ,
50+ ofNullable (service )
51+ .map (DriverService ::getUrl )
52+ .orElse (addressOfRemoteServer ), httpClientFactory );
53+ serviceOptional = ofNullable (service );
8354 }
8455
85- public AppiumCommandExecutor (Map <String , AppiumCommandInfo > additionalCommands ,
86- DriverService service ) {
87- this (additionalCommands , service , new ApacheHttpClient . Factory () );
56+ public AppiumCommandExecutor (Map <String , CommandInfo > additionalCommands , DriverService service ,
57+ HttpClient . Factory httpClientFactory ) {
58+ this (additionalCommands , checkNotNull ( service ), null , httpClientFactory );
8859 }
8960
90- public URL getAddressOfRemoteServer () {
91- return remoteServer ;
61+ public AppiumCommandExecutor (Map <String , CommandInfo > additionalCommands ,
62+ URL addressOfRemoteServer , HttpClient .Factory httpClientFactory ) {
63+ this (additionalCommands , null , checkNotNull (addressOfRemoteServer ), httpClientFactory );
9264 }
9365
94- private Response doExecute (Command command ) throws IOException , WebDriverException {
95- if (command .getSessionId () == null ) {
96- if (QUIT .equals (command .getName ())) {
97- return new Response ();
98- }
99- if (!GET_ALL_SESSIONS .equals (command .getName ())
100- && !NEW_SESSION .equals (command .getName ())) {
101- throw new NoSuchSessionException (
102- "Session ID is null. Using WebDriver after calling quit()?" );
103- }
104- }
105-
106- if (NEW_SESSION .equals (command .getName ())) {
107- if (commandCodec != null ) {
108- throw new SessionNotCreatedException ("Session already exists" );
109- }
110- AppiumProtocolHandShake handshake = new AppiumProtocolHandShake ();
111- AppiumProtocolHandShake .Result result = handshake .createSession (client , command );
112- Dialect dialect = result .getDialect ();
113- commandCodec = dialect .getCommandCodec ();
114-
115- additionalCommands .forEach ((key , value ) -> {
116- checkNotNull (key );
117- checkNotNull (value );
118- commandCodec .defineCommand (key , value .getMethod (), value .getUrl ());
119- } );
120-
121- responseCodec = dialect .getResponseCodec ();
122- return result .createResponse ();
123- }
12466
125- if ( commandCodec == null || responseCodec == null ) {
126- throw new WebDriverException (
127- "No command or response codec has been defined. Unable to proceed" );
128- }
67+ public AppiumCommandExecutor ( Map < String , CommandInfo > additionalCommands ,
68+ URL addressOfRemoteServer ) {
69+ this ( additionalCommands , addressOfRemoteServer , new ApacheHttpClient . Factory () );
70+ }
12971
130- HttpRequest httpRequest = commandCodec .encode (command );
131- try {
132- HttpResponse httpResponse = client .execute (httpRequest , true );
133-
134- Response response = responseCodec .decode (httpResponse );
135- if (response .getSessionId () == null ) {
136- if (httpResponse .getTargetHost () != null ) {
137- response .setSessionId (HttpSessionId .getSessionId (httpResponse .getTargetHost ()));
138- } else {
139- response .setSessionId (command .getSessionId ().toString ());
140- }
141- }
142- if (QUIT .equals (command .getName ())) {
143- client .close ();
144- }
145- return response ;
146- } catch (UnsupportedCommandException e ) {
147- if (e .getMessage () == null || "" .equals (e .getMessage ())) {
148- throw new UnsupportedOperationException (
149- "No information from server. Command name was: " + command .getName (),
150- e .getCause ());
151- }
152- throw e ;
153- }
72+ public AppiumCommandExecutor (Map <String , CommandInfo > additionalCommands ,
73+ DriverService service ) {
74+ this (additionalCommands , service , new ApacheHttpClient .Factory ());
15475 }
15576
156- @ Override public Response execute (Command command ) throws IOException , WebDriverException {
157- if (DriverCommand .NEW_SESSION .equals (command .getName ()) && service != null ) {
158- service .start ();
77+ @ Override public Response execute (Command command ) throws WebDriverException {
78+ if (DriverCommand .NEW_SESSION .equals (command .getName ())) {
79+ serviceOptional .ifPresent (driverService -> {
80+ try {
81+ driverService .start ();
82+ } catch (IOException e ) {
83+ throw new WebDriverException (e .getMessage (), e );
84+ }
85+ });
15986 }
16087
16188 try {
162- return doExecute (command );
89+ return super . execute (command );
16390 } catch (Throwable t ) {
164- Throwable rootCause = getRootCause (t );
91+ Throwable rootCause = Throwables . getRootCause (t );
16592 if (rootCause instanceof ConnectException
166- && rootCause .getMessage ().contains ("Connection refused" )
167- && service != null ) {
168- if (service .isRunning ()) {
169- throw new WebDriverException ("The session is closed!" , t );
170- }
171-
172- if (! service . isRunning ()) {
173- throw new WebDriverException ( "The appium server has accidentally died!" , t );
174- }
93+ && rootCause .getMessage ().contains ("Connection refused" )) {
94+ throw serviceOptional . map ( service -> {
95+ if (service .isRunning ()) {
96+ return new WebDriverException ("The session is closed!" , rootCause );
97+ }
98+
99+ return new WebDriverException ( "The appium server has accidentally died!" , rootCause );
100+ }). orElseGet (( Supplier < WebDriverException >) () ->
101+ new WebDriverException ( rootCause . getMessage (), rootCause ));
175102 }
176103 throwIfUnchecked (t );
177104 throw new WebDriverException (t );
178105 } finally {
179- if (DriverCommand .QUIT .equals (command .getName ()) && service != null ) {
180- service . stop ( );
106+ if (DriverCommand .QUIT .equals (command .getName ())) {
107+ serviceOptional . ifPresent ( DriverService :: stop );
181108 }
182109 }
183110 }
184-
185- }
111+ }
0 commit comments