org.uiautomation.ios.wkrdp.internal.WebKitRemoteDebugProtocol Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012-2013 eBay Software Foundation and ios-driver committers
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.uiautomation.ios.wkrdp.internal;
import com.google.common.collect.ImmutableMap;
import org.json.JSONException;
import org.json.JSONObject;
import org.openqa.selenium.WebDriverException;
import org.uiautomation.ios.utils.PlistManager;
import org.uiautomation.ios.wkrdp.MessageHandler;
import org.uiautomation.ios.wkrdp.MessageListener;
import org.uiautomation.ios.wkrdp.RemoteExceptionException;
import org.uiautomation.ios.wkrdp.ResponseFinder;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
/**
* Communication logic for the WKRDP to connect to an app, and to a specific webview inside that
* app.
*
* @see WebKitRemoteDebugProtocol#sendWebkitCommand(org.json.JSONObject, int) to use the protocol
* itself.
*/
public abstract class WebKitRemoteDebugProtocol {
private static final Logger log = Logger.getLogger(WebKitRemoteDebugProtocol.class.getName());
protected final MessageHandler handler;
private Thread listen;
private String connectionId;
private String bundleId;
private final PlistManager plist = new PlistManager();
private final static String senderBase = "E0F4C128-F4FF-4D45-A538-BA382CD660";
private int commandId = 0;
private volatile boolean keepGoing = true;
private volatile boolean readyToBeStopped = true;
public abstract void start();
public abstract void stop();
protected abstract void read() throws Exception;
protected abstract void sendMessage(String message);
protected void startListenerThread() {
listen = new Thread(new Runnable() {
@Override
public void run() {
try {
readyToBeStopped = false;
keepGoing = true;
while (keepGoing) {
read();
sleepTight(50);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
readyToBeStopped = true;
}
}
});
listen.start();
}
public WebKitRemoteDebugProtocol(MessageListener listener,
ResponseFinder... finders) {
this.handler = new DefaultMessageHandler(listener, finders);
}
public void addListener(MessageListener listener) {
handler.addListener(listener);
}
public void register() {
if (connectionId != null) {
throw new WebDriverException("Session already created.");
}
connectionId = UUID.randomUUID().toString();
Map var = ImmutableMap.of("$WIRConnectionIdentifierKey", connectionId);
sendSystemCommand(PlistManager.SET_CONNECTION_KEY, var);
}
public void connect(String bundleId) {
if (connectionId == null) {
throw new WebDriverException("Cannot connect to app " + bundleId + ".Call register first.");
}
Map var = ImmutableMap.of
(
"$WIRConnectionIdentifierKey", this.connectionId,
"$bundleId", bundleId
);
sendSystemCommand(PlistManager.CONNECT_TO_APP, var);
this.bundleId = bundleId;
}
public void attachToPage(int pageId) {
String senderKey = generateSenderString(pageId);
if (connectionId == null || bundleId == null) {
throw new WebDriverException("You need to call register and connect first.");
}
Map var = ImmutableMap.of
(
"$WIRConnectionIdentifierKey", connectionId,
"$bundleId", bundleId,
"$WIRSenderKey", senderKey,
"$WIRPageIdentifierKey", "" + pageId
);
sendSystemCommand(PlistManager.SET_SENDER_KEY, var);
}
private void sendSystemCommand(String templateName, Map variables) {
String xml = plist.loadFromTemplate(templateName);
for (String key : variables.keySet()) {
xml = xml.replace(key, variables.get(key));
}
sendMessage(xml);
}
public synchronized JSONObject sendWebkitCommand(JSONObject command, int pageId) {
String sender = generateSenderString(pageId);
try {
commandId++;
command.put("id", commandId);
long start = System.currentTimeMillis();
String xml = plist.JSONCommand(command);
Map var = ImmutableMap.of
(
"$WIRConnectionIdentifierKey", connectionId,
"$bundleId", bundleId,
"$WIRSenderKey", sender,
"$WIRPageIdentifierKey", "" + pageId
);
for (String key : var.keySet()) {
xml = xml.replace(key, var.get(key));
}
sendMessage(xml);
JSONObject response = handler.getResponse(command.getInt("id"));
JSONObject error = response.optJSONObject("error");
if (error != null) {
throw new RemoteExceptionException(error, command);
} else if (response.optBoolean("wasThrown", false)) {
throw new WebDriverException("remote JS exception " + response.toString(2));
} else {
log.fine(System.currentTimeMillis() + "\t\t" + (System.currentTimeMillis() - start) + "ms\t"
+ command.getString("method") + " " + command);
JSONObject res = response.getJSONObject("result");
if (res == null) {
System.err.println("GOT a null result from " + response.toString(2));
}
return res;
}
} catch (JSONException e) {
throw new WebDriverException(e);
}
}
private String generateSenderString(int pageIdentifierKey) {
if (pageIdentifierKey < 10) {
return senderBase + "0" + pageIdentifierKey;
} else {
return senderBase + pageIdentifierKey;
}
}
public void stopListenerThread() {
if (handler != null) {
handler.stop();
}
keepGoing = false;
if (listen != null) {
listen.interrupt();
}
while (!readyToBeStopped) {
sleepTight(50);
}
}
private static void sleepTight(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
}
}