1
0
mirror of synced 2026-05-22 18:53:15 +00:00

Add java sources and projects

This commit is contained in:
Yury Semikhatsky
2020-09-25 11:43:29 -07:00
parent 808271cd7b
commit bf1e53b8d1
39 changed files with 19310 additions and 0 deletions
+3
View File
@@ -9,6 +9,9 @@
*.zip
*.tar.gz
# Maven output dir
target/
.DS_Store
*.swp
.vscode
+3
View File
@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="api-generator" />
</profile>
</annotationProcessing>
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft</groupId>
<artifactId>api-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,255 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.tools;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.*;
import java.nio.file.FileSystems;
import java.util.*;
import java.util.stream.Collectors;
public class ApiGenerator {
private List<String> output;
private Set<String> innerTypes;
private static Map<String, String> tsToJavaMethodName = new HashMap<>();
static {
tsToJavaMethodName.put("continue", "continue_");
tsToJavaMethodName.put("$eval", "evalOnSelector");
tsToJavaMethodName.put("$$eval", "evalOnSelectorAll");
tsToJavaMethodName.put("$", "querySelector");
tsToJavaMethodName.put("$$", "querySelectorAll");
tsToJavaMethodName.put("goto", "navigate");
}
private static String header = "/**\n" +
" * Copyright (c) Microsoft Corporation.\n" +
" *\n" +
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
" * you may not use this file except in compliance with the License.\n" +
" * You may obtain a copy of the License at\n" +
" *\n" +
" * http://www.apache.org/licenses/LICENSE-2.0\n" +
" *\n" +
" * Unless required by applicable law or agreed to in writing, software\n" +
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
" * See the License for the specific language governing permissions and\n" +
" * limitations under the License.\n" +
" */\n" +
"\n" +
"package com.microsoft.playwright;\n";
ApiGenerator(Reader reader) throws IOException {
JsonObject api = new Gson().fromJson(reader, JsonObject.class);
File cwd = FileSystems.getDefault().getPath(".").toFile();
File dir = new File(cwd, "../lib/src/main/java/com/microsoft/playwright");
System.out.println("Writing files to: " + dir.getCanonicalPath());
dir.mkdirs();
for (Map.Entry<String, JsonElement> entry: api.entrySet()) {
innerTypes = new HashSet<>();
output = new ArrayList<>();
String name = entry.getKey();
output.add(header);
output.add("import java.util.*;");
output.add("import java.util.function.BiConsumer;");
output.add("");
output.add("interface " + name + "{");
generateInterface(entry.getValue().getAsJsonObject(), " ");
output.add("}");
output.add("\n");
String text = String.join("\n", output);
FileWriter writer = new FileWriter(new File(dir, name + ".java"));
writer.write(text);
writer.close();
}
}
private void generateInterface(JsonObject docClass, String offset) {
JsonObject members = docClass.get("members").getAsJsonObject();
for (Map.Entry<String, JsonElement> m : members.entrySet())
generateMember(m.getValue().getAsJsonObject(), offset);
}
private void generateMember(JsonObject docMember, String offset) {
String kind = docMember.get("kind").getAsString();
String name = docMember.get("name").getAsString();
if ("method".equals(kind)) {
String type = convertReturnType(docMember.get("type"));
StringBuilder args = new StringBuilder();
if (docMember.get("args") != null) {
for (Map.Entry<String, JsonElement> arg : docMember.get("args").getAsJsonObject().entrySet()) {
String argName = arg.getKey();
String argType = arg.getValue().getAsJsonObject().get("type").getAsJsonObject().get("name").getAsString();
argType = convertBuiltinType(argType);
if (argType.equals("Object")) {
argType = generateParamClass(name, argName, arg.getValue().getAsJsonObject().get("type").getAsJsonObject(), offset);
}
if (argType.equals("function(Route, Request)")) {
argType = "BiConsumer<Route, Request>";
} else if (argType.equals("EvaluationArgument")) {
argType = "Object";
} else if (argType.equals("number")) {
argType = "int";
} else if (argType.contains("|\"")) {
String enumName = enumName(name, argName);
generateEnum(enumName, argType, "", offset);
argType = enumName;
} else if (argType.contains("|")) {
argType = "String";
} else if (argType.contains("function")) {
// js functions are always passed as text in java.
if (argName.startsWith("playwright") || argName.startsWith("page")) {
argType = "String";
}
}
if (args.length() > 0) {
args.append(", ");
}
args.append(argType).append(" ").append(argName);
}
}
if (tsToJavaMethodName.containsKey(name))
name = tsToJavaMethodName.get(name);
output.add(offset + type + " " + name + "(" + args + ");");
}
}
private String generateParamClass(String methodName, String argName, JsonObject json, String offset) {
String className = toTitle(methodName) + toTitle(argName);
output.add("");
output.add(offset + "class " + className + " {");
String memberOffset = offset + " ";
for (Map.Entry<String, JsonElement> e : json.get("properties").getAsJsonObject().entrySet()) {
String name = e.getKey();
String type = e.getValue().getAsJsonObject().get("type").getAsJsonObject().get("name").getAsString();
if ("modifiers".equals(name)) {
if (!type.equals("Array<\"Alt\"|\"Control\"|\"Meta\"|\"Shift\">"))
throw new RuntimeException("Unexpected type of modifiers: " + type);
generateEnum("Modifier", "\"Alt\"|\"Control\"|\"Meta\"|\"Shift\"", className, memberOffset);
type = "Set<Modifier>";
}
if ("media".equals(name)) {
if (!type.equals("null|\"print\"|\"screen\""))
throw new RuntimeException("Unexpected type of media: " + type);
type = "Media";
generateEnum(type, "\"print\"|\"screen\"", className, memberOffset);
}
if ("pdf".equals(methodName) && (name.equals("width") || name.equals("height"))) {
if (!type.equals("string|number"))
throw new RuntimeException("Unexpected type of pdf dimensions: " + type);
type = "String";
}
if ("continue".equals(methodName) && name.equals("postData")) {
if (!type.equals("string|Buffer"))
throw new RuntimeException("Unexpected type of pdf dimensions: " + type);
type = "String";
}
if ("fulfill".equals(methodName) && name.equals("body")) {
if (!type.equals("string|Buffer"))
throw new RuntimeException("Unexpected type of pdf dimensions: " + type);
type = "String";
}
if ("waitForNavigation".equals(methodName) && argName.equals("options") && name.equals("url")) {
if (!type.equals("string|RegExp|Function"))
throw new RuntimeException("Unexpected type of pdf dimensions: " + type);
type = "String";
}
if (type.contains("|\"") && type.endsWith("\"")) {
type = type.replace("null|", "");
String enumName = toTitle(name);
generateEnum(enumName, type, className, memberOffset);
type = enumName;
}
if ("ignoreDefaultArgs".equals(name)) {
type = "Boolean";
}
type = convertBuiltinType(type);
type = replacePrimitiveWithBoxedType(type);
output.add(memberOffset + type + " " + name + ";");
}
output.add(offset + "}");
return className;
}
private static String toTitle(String name) {
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
}
private static String enumName(String methodName, String argName) {
if (methodName.startsWith("waitFor")) {
return methodName.substring("waitFor".length());
}
return toTitle(argName);
}
private void generateEnum(String name, String values, String scope, String offset) {
if (!innerTypes.add(scope + values)) {
return;
}
String[] split = values.split("\\|");
List<String> enumValues = Arrays.stream(split).map(s -> s.substring(1, s.length() - 1).replace("-", "_").toUpperCase()).collect(Collectors.toList());
output.add(offset + "enum " + name + " { " + String.join(", ", enumValues) + " }");
}
private static String convertReturnType(JsonElement jsonType) {
String type = jsonType.isJsonNull() ? "void" : jsonType.getAsJsonObject().get("name").getAsString();
if ("Promise".equals(type)) {
type = "void";
}
// Java API is sync just strip Promise<>
if (type.startsWith("Promise<")) {
type = type.substring("Promise<".length(), type.length() - 1);
}
return convertBuiltinType(type);
}
private static String replacePrimitiveWithBoxedType(String type) {
return type.replace("int", "Integer")
.replace("boolean", "Boolean")
.replace("double", "Double");
}
private static String convertBuiltinType(String type) {
return type.replace("string|number|boolean", "String")
.replace("Array<", "List<")
.replace("string", "String")
.replace("number", "int")
.replace("Serializable", "Object")
.replace("Buffer", "byte[]")
.replace("ChildProcess", "Object")
.replace("Object<", "Map<")
.replace("null|", "");
}
public static void main(String[] args) throws IOException {
File cwd = FileSystems.getDefault().getPath(".").toFile();
System.out.println(cwd.getCanonicalPath());
File file = new File(cwd, "src/main/resources/api.json");
System.out.println("Reading from: " + file.getCanonicalPath());
new ApiGenerator(new FileReader(file));
}
}
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
/node_modules/
.DS_Store
*.swp
.vscode
package-lock.json
+17
View File
@@ -0,0 +1,17 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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.
*/
require('playwright/lib/server');
+15
View File
@@ -0,0 +1,15 @@
{
"name": "driver",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"dependencies": {
"playwright": "^1.4.2"
}
}
+3
View File
@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="lib" />
</profile>
</annotationProcessing>
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft</groupId>
<artifactId>playwright</artifactId>
<version>0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,41 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class Browser extends ChannelOwner {
Browser(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
BrowserContext newContext() {
return newContext(new BrowserNewContextOptions());
}
BrowserContext newContext(BrowserNewContextOptions options) {
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
JsonElement result = sendMessage("newContext", params);
return connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("context").get("guid").getAsString());
}
void close() {
sendMessage("close", new JsonObject());
}
}
@@ -0,0 +1,44 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.function.Supplier;
public class BrowserContext extends ChannelOwner {
protected BrowserContext(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
Page newPage() {
JsonObject params = new JsonObject();
JsonElement result = sendMessage("newPage", params);
return connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("page").get("guid").getAsString());
}
public Supplier<Page> waitForPage() {
Supplier<JsonObject> pageSupplier = waitForEvent("page");
return () -> {
JsonObject params = pageSupplier.get();
String guid = params.getAsJsonObject("page").get("guid").getAsString();
return connection.getExistingObject(guid);
};
}
}
@@ -0,0 +1,65 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import java.util.LinkedHashMap;
public class BrowserNewContextOptions {
Boolean noDefaultViewport;
public static class Viewport {
// TODO: int is preferred here
int width;
int height;
}
Viewport viewport;
Boolean ignoreHTTPSErrors;
Boolean javaScriptEnabled;
Boolean bypassCSP;
String userAgent;
String locale;
String timezoneId;
public static class Geolocation {
// TODO: can we use int somehow?
Double longitude;
Double latitude;
Double accuracy;
};
Geolocation geolocation;
String[] permissions;
LinkedHashMap<String, String> extraHTTPHeaders;
Boolean offline;
public static class HttpCredentials {
String username;
String password;
}
HttpCredentials httpCredentials;
Integer deviceScaleFactor;
Boolean isMobile;
Boolean hasTouch;
enum ColorScheme {
// TODO: noPreference => no-preference
dark, light, noPreference
}
ColorScheme colorScheme;
Boolean acceptDownloads;
Boolean _recordVideos;
public static class _VideoSize {
int width;
int height;
}
_VideoSize _videoSize;
}
@@ -0,0 +1,45 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class BrowserType extends ChannelOwner {
BrowserType(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
public String executablePath() {
return initializer.get("executablePath").getAsString();
}
public String name() {
return initializer.get("name").getAsString();
}
Browser launch() {
return launch(new BrowserTypeLaunchOptions());
}
Browser launch(BrowserTypeLaunchOptions options) {
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
JsonElement result = sendMessage("launch", params);
return connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("browser").get("guid").getAsString());
}
}
@@ -0,0 +1,47 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
import java.util.LinkedHashMap;
public class BrowserTypeLaunchOptions {
String executablePath;
String[] args;
Boolean ignoreAllDefaultArgs;
String[] ignoreDefaultArgs;
Boolean handleSIGINT;
Boolean handleSIGTERM;
Boolean handleSIGHUP;
Integer timeout;
LinkedHashMap<String, String> env;
Boolean headless;
Boolean devtools;
public static class Proxy {
String server;
String bypass;
String username;
String password;
}
Proxy proxy;
String downloadsPath;
String _videosPath;
JsonObject firefoxUserPrefs;
Boolean chromiumSandbox;
Integer slowMo;
}
@@ -0,0 +1,106 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
class ChannelOwner {
final Connection connection;
private final ChannelOwner parent;
private final Map<String, ChannelOwner> objects = new HashMap();
final String type;
final String guid;
// private T channel;
final JsonObject initializer;
Map<String, ArrayList<CompletableFuture<JsonObject>>> futureEvents = new HashMap<>();
protected ChannelOwner(ChannelOwner parent, String type, String guid, JsonObject initializer) {
this(parent.connection, parent, type, guid, initializer);
}
protected ChannelOwner(Connection connection, String type, String guid) {
this(connection, null, type, guid, new JsonObject());
}
private ChannelOwner(Connection connection, ChannelOwner parent, String type, String guid, JsonObject initializer) {
this.connection = connection;
this.parent = parent;
this.type = type;
this.guid = guid;
this.initializer = initializer;
connection.registerObject(guid, this);
if (parent != null)
parent.objects.put(guid, this);
}
public void dispose() {
}
JsonElement sendMessage(String method, JsonObject params) {
return connection.sendMessage(guid, method, params);
}
void sendMessageNoWait(String method, JsonObject params) {
connection.sendMessageNoWait(guid, method, params);
}
protected Supplier<JsonObject> waitForEvent(String event) {
ArrayList<CompletableFuture<JsonObject>> futures = futureEvents.get(event);
if (futures == null) {
futures = new ArrayList<>();
futureEvents.put(event, futures);
}
CompletableFuture<JsonObject> result = new CompletableFuture<>();
futures.add(result);
return () -> {
while (!result.isDone()) {
connection.processOneMessage();
}
try {
return result.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
};
}
final void onEvent(String event, JsonObject parameters) {
handleEvent(event, parameters);
ArrayList<CompletableFuture<JsonObject>> futures = futureEvents.remove(event);
if (futures == null)
return;
for (CompletableFuture<JsonObject> f : futures) {
f.complete(parameters);
}
}
protected void handleEvent(String event, JsonObject params) {
}
}
@@ -0,0 +1,224 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
class Message {
int id;
String guid;
String method;
JsonObject params;
JsonElement result;
JsonObject error;
@Override
public String toString() {
return "Message{" +
"id='" + id + '\'' +
", guid='" + guid + '\'' +
", method='" + method + '\'' +
", params=" + (params == null ? null : "<...>") +
", result='" + result + '\'' +
", error='" + error + '\'' +
'}';
}
}
public class Connection {
private final Transport transport;
private final Map<String, ChannelOwner> objects = new HashMap();
private final Root root;
private int lastId = 0;
private final Map<Integer, CompletableFuture<Message>> callbacks = new HashMap();
class Root extends ChannelOwner {
Root(Connection connection) {
super(connection, "", "");
}
}
public Connection(InputStream in, OutputStream out) {
transport = new Transport(in, out);
root = new Root(this);
}
public JsonElement sendMessage(String guid, String method, JsonObject params) {
CompletableFuture<Message> result = internalSendMessage(guid, method, params);
while (!result.isDone()) {
processOneMessage();
}
try {
return result.get().result;
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
public void sendMessageNoWait(String guid, String method, JsonObject params) {
internalSendMessage(guid, method, params);
}
private CompletableFuture<Message> internalSendMessage(String guid, String method, JsonObject params) {
int id = ++lastId;
CompletableFuture<Message> result = new CompletableFuture();
callbacks.put(id, result);
JsonObject message = new JsonObject();
message.addProperty("id", id);
message.addProperty("guid", guid);
message.addProperty("method", method);
message.add("params", params);
transport.send(new Gson().toJson(message));
return result;
}
public ChannelOwner waitForObjectWithKnownName(String guid) {
while (!objects.containsKey(guid)) {
processOneMessage();
}
return objects.get(guid);
}
public <T> T getExistingObject(String guid) {
T result = (T) objects.get(guid);
if (result == null)
throw new RuntimeException("Object doesn't exist: " + guid);
return result;
}
void registerObject(String guid, ChannelOwner object) {
objects.put(guid, object);
}
void unregisterObject(String guid, ChannelOwner object) {
objects.remove(guid);
}
void processOneMessage() {
String messageString = transport.read();
Gson gson = new Gson();
Message message = gson.fromJson(messageString, Message.class);
dispatch(message);
}
private void dispatch(Message message) {
// System.out.println("Message: " + message.method + " " + message.id);
if (message.id != 0) {
CompletableFuture<Message> callback = callbacks.get(message.id);
if (callback == null) {
throw new RuntimeException("Cannot find command to respond: " + message.id);
}
callbacks.remove(message.id);
// System.out.println("Message: " + message.id + " " + message);
if (message.error == null)
callback.complete(message);
else
callback.completeExceptionally(new RuntimeException(message.error.toString()));
return;
}
// TODO: throw?
if (message.method == null)
return;
if (message.method.equals("__create__")) {
createRemoteObject(message.guid, message.params);
return;
}
if (message.method.equals("__dispose__")) {
ChannelOwner object = objects.get(message.guid);
if (object == null)
throw new RuntimeException("Cannot find object to dispose: " + message.guid);
object.dispose();
return;
}
ChannelOwner object = objects.get(message.guid);
if (object == null)
throw new RuntimeException("Cannot find object to call " + message.method + ": " + message.guid);
// object._channel.emit(message.method, this._replaceGuidsWithChannels(message.params));
object.onEvent(message.method, message.params);
}
private ChannelOwner createRemoteObject(String parentGuid, JsonObject params) {
String type = params.get("type").getAsString();
String guid = params.get("guid").getAsString();
ChannelOwner parent = objects.get(parentGuid);
if (parent == null)
throw new RuntimeException("Cannot find parent object " + parentGuid + " to create " + guid);
JsonObject initializer = params.getAsJsonObject("initializer");
ChannelOwner result = null;
// initializer = this._replaceGuidsWithChannels(initializer);
switch (type) {
case "BrowserType":
result = new BrowserType(parent, type, guid, initializer);
break;
case "Browser":
result = new Browser(parent, type, guid, initializer);
break;
case "BrowserContext":
result = new BrowserContext(parent, type, guid, initializer);
break;
case "ConsoleMessage":
result = new ConsoleMessage(parent, type, guid, initializer);
break;
case "Dialog":
result = new Dialog(parent, type, guid, initializer);
break;
case "Download":
result = new Download(parent, type, guid, initializer);
break;
case "Electron":
// result = new Playwright(parent, type, guid, initializer);
break;
case "Frame":
result = new Frame(parent, type, guid, initializer);
break;
case "JSHandle":
// result = new JSHandle(parent, type, guid, initializer);
break;
case "Page":
result = new Page(parent, type, guid, initializer);
break;
case "Playwright":
result = new Playwright(parent, type, guid, initializer);
break;
case "Request":
result = new Request(parent, type, guid, initializer);
break;
case "Response":
result = new Response(parent, type, guid, initializer);
break;
case "Selectors":
// result = new Playwright(parent, type, guid, initializer);
break;
default:
throw new RuntimeException("Unknown type " + type);
}
return result;
}
}
@@ -0,0 +1,55 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class ConsoleMessage extends ChannelOwner {
public ConsoleMessage(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
public String type() {
return initializer.get("type").getAsString();
}
public String text() {
return initializer.get("text").getAsString();
}
// args(): JSHandle[] {
// return this._initializer.args.map(JSHandle.from);
// }
public static class Location {
String url;
int lineNumber;
int columnNumber;
@Override
public String toString() {
return url +
":" + lineNumber +
":" + columnNumber;
}
}
public Location location() {
return new Gson().fromJson(initializer.get("location"), Location.class);
}
}
@@ -0,0 +1,56 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
public class Dialog extends ChannelOwner {
private boolean handled;
Dialog(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
public void accept(String promptText) {
handled = true;
JsonObject params = new JsonObject();
if (promptText != null)
params.addProperty("promptText", promptText);
sendMessageNoWait("accept", params);
}
public void dismiss() {
handled = true;
sendMessageNoWait("dismiss", new JsonObject());
}
public String defaultValue() {
return initializer.get("defaultValue").getAsString();
}
public String message() {
return initializer.get("message").getAsString();
}
// public enum Type { Alert, BeforeUnload, Confirm, Prompt }
public String type() {
return initializer.get("type").getAsString();
}
boolean isHandled() {
return handled;
}
}
@@ -0,0 +1,40 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class Download extends ChannelOwner {
public Download(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
public String url() {
return initializer.get("url").getAsString();
}
public String suggestedFilename() {
return initializer.get("suggestedFilename").getAsString();
}
public String path() {
JsonObject params = new JsonObject();
JsonElement result = sendMessage("path", params);
return result.getAsJsonObject().get("path").getAsString();
}
}
@@ -0,0 +1,161 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.*;
import static com.microsoft.playwright.impl.Helpers.isFunctionBody;
public class Frame extends ChannelOwner {
Page page;
Frame(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
public Response navigate(String url) {
return navigate(url, new NavigateOptions());
}
public Response navigate(String url, NavigateOptions options) {
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
params.addProperty("url", url);
JsonElement result = sendMessage("goto", params);
System.out.println("result = " + new Gson().toJson(result));
return connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("response").get("guid").getAsString());
}
public void click(String selector) {
JsonObject params = new JsonObject();
params.addProperty("selector", selector);
JsonElement result = sendMessage("click", params);
}
private static SerializedValue serializeValue(Object value) {
SerializedValue result = new SerializedValue();
if (value == null)
result.v = "undefined";
else if (value instanceof Double) {
double d = ((Double) value).doubleValue();
if (d == Double.POSITIVE_INFINITY)
result.v = "Infinity";
else if (d == Double.NEGATIVE_INFINITY)
result.v = "-Infinity";
else if (d == -0)
result.v = "-0";
else if (Double.isNaN(d))
result.v="NaN";
else
result.n = d;
}
// if (value instanceof Date)
else if (value instanceof Boolean)
result.b = (Boolean) value;
else if (value instanceof Integer)
result.n = (Integer) value;
else if (value instanceof String)
result.s = (String) value;
else if (value instanceof List) {
List<SerializedValue> list = new ArrayList<>();
for (Object o : (List) value)
list.add(serializeValue(o));
result.a = list.toArray(new SerializedValue[0]);
} else if (value instanceof Map) {
List<SerializedValue.O> list = new ArrayList<>();
Map<String, Object> map = (Map<String, Object>) value;
for (Map.Entry<String, Object> e : map.entrySet()) {
SerializedValue.O o = new SerializedValue.O();
o.k = e.getKey();
o.v = serializeValue(e.getValue());
list.add(o);
}
result.o = list.toArray(new SerializedValue.O[0]);
} else
throw new RuntimeException("Unsupported type of argument: " + value);
return result;
}
private static SerializedArgument serializeArgument(Object arg) {
SerializedArgument result = new SerializedArgument();
result.value = serializeValue(arg);
result.handles = new Channel[0];
return result;
}
private static <T> T deserialize(SerializedValue value) {
if (value.n != null) {
if (value.n.doubleValue() == (double) value.n.intValue())
return (T) Integer.valueOf(value.n.intValue());
return (T) Double.valueOf(value.n.doubleValue());
}
if (value.b != null)
return (T) value.b;
if (value.s != null)
return (T) value.s;
if (value.v != null) {
switch (value.v) {
case "undefined":
return null;
case "Infinity":
return (T) Double.valueOf(Double.POSITIVE_INFINITY);
case "-Infinity":
return (T) Double.valueOf(Double.NEGATIVE_INFINITY);
case "-0":
return (T) Double.valueOf(-0);
case "NaN":
return (T) Double.valueOf(Double.NaN);
default:
throw new RuntimeException("Unexpected value: " + value.v);
}
}
if (value.a != null) {
List list = new ArrayList();
for (SerializedValue v : value.a)
list.add(deserialize(v));
return (T) list;
}
if (value.o != null) {
Map map = new LinkedHashMap<>();
for (SerializedValue.O o : value.o)
map.put(o.k, deserialize(o.v));
return (T) map;
}
throw new RuntimeException("Unexpected result: " + new Gson().toJson(value));
}
public <T> T evalTyped(String expression) {
JsonElement json = evaluate(expression, null, false);
System.out.println("json = " + new Gson().toJson(json));
SerializedValue value = new Gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
return deserialize(value);
}
public JsonElement evaluate(String expression, Object arg, boolean forceExpression) {
JsonObject params = new JsonObject();
params.addProperty("expression", expression);
params.addProperty("world", "main");
if (!isFunctionBody(expression))
forceExpression = true;
params.addProperty("isFunction", !forceExpression);
params.add("arg", new Gson().toJsonTree(serializeArgument(arg)));
return sendMessage("evaluateExpression", params);
}
}
@@ -0,0 +1,26 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
class Helpers {
static boolean isFunctionBody(String expression) {
expression = expression.trim();
return expression.startsWith("function") ||
expression.startsWith("async ") ||
expression.contains("=>");
}
}
@@ -0,0 +1,102 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import java.io.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Playwright playwright = Playwright.create();
BrowserTypeLaunchOptions options = new BrowserTypeLaunchOptions();
options.headless = false;
// options.slowMo = 1000;
System.out.println("options = " + new Gson().toJson(options));
Browser browser = playwright.chromium.launch(options);
System.out.println("browser = " + browser);
BrowserNewContextOptions contextOptions = new BrowserNewContextOptions();
contextOptions.viewport = new BrowserNewContextOptions.Viewport();
contextOptions.viewport.width = 800;
contextOptions.viewport.height = 600;
BrowserContext context = browser.newContext(contextOptions);
Page page = context.newPage();
page.navigate("http://example.com");
// page.click("text=web browser engine");
Supplier<Page> popupSupplier = page.waitForPopup();
Supplier<Page> pageSupplier = context.waitForPage();
page.evaluate("window.open('http://example.com'); 13");
{
JsonElement r = page.evaluate("function foo(a) { return a + 1; }", 20);
System.out.println("r = " + new Gson().toJson(r));
}
{
List<Integer> r = page.evalTyped("function foo() { return [1,2,3]; }");
System.out.println("r = " + new Gson().toJson(r));
int p = r.get(0).intValue() + 1;
}
{
int r = page.evalTyped("function foo() { return 7; }");
System.out.println("int r = " + new Gson().toJson(r));
}
{
double r = page.evalTyped("function foo() { return 7.2; }");
System.out.println("double r = " + new Gson().toJson(r));
}
Page popup = popupSupplier.get();
System.out.println("popup = " + popup);
Page page2 = pageSupplier.get();
System.out.println(page2 == popup);
page.addDialogHandler(d -> {
System.out.println("Got dialog type: " + d.type());
System.out.println(" message = " + d.message());
d.accept("abc");
});
page.evaluate("alert('Hi there!')");
System.out.println("After alert");
page.addConsoleListener(m -> {
System.out.println("Got console message type: " + m.type());
System.out.println(" text = " + m.text());
System.out.println(" location = " + m.location());
});
page.evaluate("console.log('A message')");
browser.close();
// Disconnect and terminate the threads?
// playwright.close();
System.out.println("\nDONE.");
System.exit(0);
}
}
@@ -0,0 +1,28 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
public class NavigateOptions {
Integer timeout;
enum WaitUntil {
load,
domcontentloaded,
networkidle
}
WaitUntil waitUntil = WaitUntil.load;
String referer;
}
@@ -0,0 +1,114 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class Page extends ChannelOwner {
private final Frame mainFrame;
private final List<DialogHandler> dialogHandlers = new ArrayList<>();
private final List<ConsoleListener> consoleListeners = new ArrayList<>();
Page(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
mainFrame = connection.getExistingObject(initializer.getAsJsonObject("mainFrame").get("guid").getAsString());
mainFrame.page = this;
}
public Response navigate(String url) {
return navigate(url, new NavigateOptions());
}
public Response navigate(String url, NavigateOptions options) {
return mainFrame.navigate(url, options);
}
public void click(String selector) {
mainFrame.click(selector);
}
public Supplier<Page> waitForPopup() {
Supplier<JsonObject> popupSupplier = waitForEvent("popup");
return () -> {
JsonObject params = popupSupplier.get();
String guid = params.getAsJsonObject("page").get("guid").getAsString();
return connection.getExistingObject(guid);
};
}
public interface DialogHandler {
void handle(Dialog d);
}
public void addDialogHandler(DialogHandler handler) {
dialogHandlers.add(handler);
}
public void removeDialogHandler(DialogHandler handler) {
dialogHandlers.remove(handler);
}
protected void handleEvent(String event, JsonObject params) {
if ("dialog".equals(event)) {
String guid = params.getAsJsonObject("dialog").get("guid").getAsString();
Dialog dialog = connection.getExistingObject(guid);
for (DialogHandler handler: new ArrayList<>(dialogHandlers))
handler.handle(dialog);
// If no action taken dismiss dialog to not hang.
if (!dialog.isHandled())
dialog.dismiss();
} else if ("console".equals(event)) {
String guid = params.getAsJsonObject("message").get("guid").getAsString();
ConsoleMessage message = connection.getExistingObject(guid);
for (ConsoleListener listener: new ArrayList<>(consoleListeners))
listener.handle(message);
}
}
public interface ConsoleListener {
void handle(ConsoleMessage m);
}
public void addConsoleListener(ConsoleListener listener) {
consoleListeners.add(listener);
}
public void removeConsoleListener(ConsoleListener listener) {
consoleListeners.remove(listener);
}
public <T> T evalTyped(String expression) {
return mainFrame.evalTyped(expression);
}
public JsonElement evaluate(String expression) {
return evaluate(expression, null);
}
public JsonElement evaluate(String expression, Object arg) {
return evaluate(expression, arg, false);
}
public JsonElement evaluate(String expression, Object arg, boolean forceExpression) {
return mainFrame.evaluate(expression, arg, forceExpression);
}
}
@@ -0,0 +1,49 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
public class Playwright extends ChannelOwner {
static Playwright create() throws IOException {
File cwd = FileSystems.getDefault().getPath(".").toFile();
File driver = new File(cwd, "../driver/main.js");
System.out.println("driver = " + driver.getCanonicalPath());
ProcessBuilder pb = new ProcessBuilder("node", driver.getCanonicalPath());
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
// pb.environment().put("DEBUG", "pw:pro*");
Process p = pb.start();
Connection connection = new Connection(p.getInputStream(), p.getOutputStream());
Playwright playwright = (Playwright)connection.waitForObjectWithKnownName("Playwright");
return playwright;
}
public final BrowserType chromium;
public final BrowserType firefox;
public final BrowserType webkit;
public Playwright(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
chromium = parent.connection.getExistingObject(initializer.getAsJsonObject("chromium").get("guid").getAsString());
firefox = parent.connection.getExistingObject(initializer.getAsJsonObject("firefox").get("guid").getAsString());
webkit = parent.connection.getExistingObject(initializer.getAsJsonObject("webkit").get("guid").getAsString());
}
}
@@ -0,0 +1,102 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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.
*/
// This file is generated by generate_java_rpc.js, do not edit manually.
package com.microsoft.playwright.impl;
class Binary {
}
class Channel {
}
class Metadata{
String stack;
}
class SerializedValue{
Number n;
Boolean b;
String s;
// Possible values: { 'null, 'undefined, 'NaN, 'Infinity, '-Infinity, '-0 }
String v;
String d;
public static class R {
String p;
String f;
}
R r;
SerializedValue[] a;
public static class O {
String k;
SerializedValue v;
}
O[] o;
Number h;
}
class SerializedArgument{
SerializedValue value;
Channel[] handles;
}
class AXNode{
String role;
String name;
String valueString;
Number valueNumber;
String description;
String keyshortcuts;
String roledescription;
String valuetext;
Boolean disabled;
Boolean expanded;
Boolean focused;
Boolean modal;
Boolean multiline;
Boolean multiselectable;
Boolean readonly;
Boolean required;
Boolean selected;
// Possible values: { 'checked, 'unchecked, 'mixed }
String checked;
// Possible values: { 'pressed, 'released, 'mixed }
String pressed;
Number level;
Number valuemin;
Number valuemax;
String autocomplete;
String haspopup;
String invalid;
String orientation;
AXNode[] children;
}
class SerializedError{
public static class Error {
String message;
String name;
String stack;
}
Error error;
SerializedValue value;
}
@@ -0,0 +1,25 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
public class Request extends ChannelOwner {
Request(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
}
@@ -0,0 +1,25 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
public class Response extends ChannelOwner {
Response(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
}
@@ -0,0 +1,137 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 com.microsoft.playwright.impl;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Transport {
private final BlockingQueue<String> incoming = new ArrayBlockingQueue(1000);
private final BlockingQueue<String> outgoing= new ArrayBlockingQueue(1000);
private final ReaderThread readerThread;
private final WriterThread writerThread;
Transport(InputStream input, OutputStream output) {
DataInputStream in = new DataInputStream(new BufferedInputStream(input));
readerThread = new ReaderThread(in, incoming);
readerThread.start();
// TODO: buffer?
DataOutputStream out = new DataOutputStream(output);
writerThread = new WriterThread(out, outgoing);
writerThread.start();
}
public void send(String message) {
try {
outgoing.put(message);
} catch (InterruptedException e) {
throw new RuntimeException("Failed to send message", e);
}
}
public String read() {
try {
return incoming.take();
} catch (InterruptedException e) {
throw new RuntimeException("Failed to send message", e);
}
}
}
class ReaderThread extends Thread {
private final DataInputStream in;
private final BlockingQueue<String> queue;
private static int readIntLE(DataInputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0) {
throw new EOFException();
} else {
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
}
}
ReaderThread(DataInputStream in, BlockingQueue<String> queue) {
this.in = in;
this.queue = queue;
}
@Override
public void run() {
while (!isInterrupted()) {
try {
queue.put(readMessage());
} catch (IOException e) {
e.printStackTrace();
break;
} catch (InterruptedException e) {
break;
}
}
}
private String readMessage() throws IOException {
int len = readIntLE(in);
byte[] raw = new byte[len];
in.readFully(raw, 0, len);
return new String(raw, StandardCharsets.UTF_8);
}
}
class WriterThread extends Thread {
private final DataOutputStream out;
private final BlockingQueue<String> queue;
private static void writeIntLE(DataOutputStream out, int v) throws IOException {
out.write(v >>> 0 & 255);
out.write(v >>> 8 & 255);
out.write(v >>> 16 & 255);
out.write(v >>> 24 & 255);
}
WriterThread(DataOutputStream out, BlockingQueue<String> queue) {
this.out = out;
this.queue = queue;
}
@Override
public void run() {
while (!isInterrupted()) {
try {
if (queue.isEmpty())
out.flush();
sendMessage(queue.take());
} catch (IOException e) {
e.printStackTrace();
break;
} catch (InterruptedException e) {
break;
}
}
}
private void sendMessage(String message) throws IOException {
int len = message.length();
writeIntLE(out, len);
out.writeBytes(message);
}
}