Skip to content

Commit

Permalink
Merge pull request #42 from soisetu/development
Browse files Browse the repository at this point in the history
Experimental java agent support
  • Loading branch information
sampeson authored Sep 3, 2020
2 parents a823553 + 1781649 commit bcdf4c1
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 79 deletions.
2 changes: 1 addition & 1 deletion AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ Tatu Lahtela Find All With Pseudo Class and Find Class keywords
Sakari Hoisko Dockerized linux env with X
Juho Lehtonen Optimized docker environment.
Juho Saarinen Package improvements, initial monocle support, screenshot bug fix

Turo Soisenniemi Initial java agent support
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Executing _test.sh_ runs the acceptance suite twice: first using JavaFXLibrary a
If you want the suite to run only once, you can define which type of library to use by including **local** or **remote** as an argument. For example command `test.sh remote` will execute the suite only in remote mode.

## Experimental: Headless support
Library supports headless operation utilizing [Monocle](https://wiki.openjdk.java.net/display/OpenJFX/Monocle). The support for this is still at experimental level.
Library supports headless operation utilizing [Monocle](https://wiki.openjdk.java.net/display/OpenJFX/Monocle). The support for this is still at experimental level.

### Main issues with headless function
* Scrolling doesn't work same way as with screen
Expand All @@ -97,4 +97,7 @@ Remote:
```
*** Settings ***
Library Remote http://127.0.0.1:8270 ${True} WITH NAME JavaFXLibrary
```
```

## Experimental: Java agent support
Library can be used as java agent. Launch application with `-javaagent:/path/to/javafxlibrary-<version>.jar`. Default port is 8270 and can be changed with adding `=<port>` to java agent command. Only remote library is supported. Using launch keyword is still required but instead of starting new application keyword initializes Stage for library.
3 changes: 3 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@
<addClasspath>true</addClasspath>
<mainClass>JavaFXLibrary</mainClass>
</manifest>
<manifestEntries>
<Premain-Class>JavaFXLibrary</Premain-Class>
</manifestEntries>
</archive>
</configuration>
<executions>
Expand Down
58 changes: 38 additions & 20 deletions src/main/java/JavaFXLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ public class JavaFXLibrary extends AnnotationLibrary {
add("javafxlibrary/keywords/Keywords/*.class");
add("javafxlibrary/keywords/*.class");
add("javafxlibrary/tests/*.class");
}};
}};

public JavaFXLibrary() {
this(false);
this(false);
}

public JavaFXLibrary(boolean headless) {
super(includePatterns);
if (headless) {
Expand All @@ -71,9 +71,9 @@ public JavaFXLibrary(boolean headless) {
System.setProperty("prism.text", "t2k");
TestFxAdapter.isHeadless = true;
} else {
//v4.0.15-alpha sets default robot as glass, which breaks rolling
//Forcing usage of awt robot as previous versions
System.setProperty("testfx.robot", "awt");
// v4.0.15-alpha sets default robot as glass, which breaks rolling
// Forcing usage of awt robot as previous versions
System.setProperty("testfx.robot", "awt");
}
}

Expand Down Expand Up @@ -108,7 +108,6 @@ public Object runKeyword(String keywordName, List args, Map kwargs) {
finalKwargs = kwargs;
}


AtomicReference<Object> retval = new AtomicReference<>();
AtomicReference<RuntimeException> retExcep = new AtomicReference<>();

Expand All @@ -121,12 +120,12 @@ public Object runKeyword(String keywordName, List args, Map kwargs) {
retval.set(super.runKeyword(keywordName, finalArgs, finalKwargs));
return true;

} catch (JavaFXLibraryTimeoutException jfxte){
} catch (JavaFXLibraryTimeoutException jfxte) {
// timeout already expired, catch exception and jump out
retExcep.set(jfxte);
throw jfxte;

} catch (RuntimeException e){
} catch (RuntimeException e) {
// catch exception and continue trying
retExcep.set(e);
return false;
Expand Down Expand Up @@ -165,10 +164,11 @@ public Object runKeyword(String keywordName, List args) {

List finalArgs;
// JavalibCore changes arguments of Call Method keywords to Strings after this check, so they need to handle their own objectMapping
if (!(keywordName.equals("callObjectMethod") || keywordName.equals("callObjectMethodInFxApplicationThread")))
if (!(keywordName.equals("callObjectMethod") || keywordName.equals("callObjectMethodInFxApplicationThread"))) {
finalArgs = HelperFunctions.useMappedObjects(args);
else
} else {
finalArgs = args;
}

AtomicReference<Object> retval = new AtomicReference<>();
AtomicReference<RuntimeException> retExcep = new AtomicReference<>();
Expand All @@ -182,12 +182,12 @@ public Object runKeyword(String keywordName, List args) {
retval.set(super.runKeyword(keywordName, finalArgs));
return true;

} catch (JavaFXLibraryTimeoutException jfxte){
} catch (JavaFXLibraryTimeoutException jfxte) {
// timeout already expired, catch exception and jump out
retExcep.set(jfxte);
throw jfxte;

} catch (RuntimeException e){
} catch (RuntimeException e) {
// catch exception and continue trying
retExcep.set(e);
return false;
Expand Down Expand Up @@ -227,17 +227,16 @@ public String getKeywordDocumentation(String keywordName) {
return "IOException occurred while reading the documentation file!";
}
} else if (keywordName.equals("__init__")) {
try {
try {
return FileUtils.readFileToString(new File("./src/main/java/libdoc-init-documentation.txt"), "utf-8");
} catch (IOException e) {
e.printStackTrace();
return "IOException occurred while reading the init documentation file!";
}
} else {
try {
try {
return super.getKeywordDocumentation(keywordName);
}
catch (Exception e) {
} catch (Exception e) {
return keywordName;
}
}
Expand All @@ -258,6 +257,27 @@ public static JavaFXLibrary getLibraryInstance() throws ScriptException {
}

public static void main(String[] args) throws Exception {
startServer(args);
}

public static void premain(String args) {
TestFxAdapter.isAgent = true;
Thread agentThread = new Thread(() -> {
try {
if (args == null) {
startServer();
} else {
startServer(args);
}
} catch (Exception e) {
e.printStackTrace();
}
});
agentThread.setDaemon(true);
agentThread.start();
}

public static void startServer(String... args) throws Exception {
int port = 8270;
InetAddress ipAddr = InetAddress.getLocalHost();

Expand All @@ -266,8 +286,7 @@ public static void main(String[] args) throws Exception {
System.out.println("----------------------------= JavaFXLibrary =-----------------------------");
if (args.length > 0) {
port = Integer.parseInt(args[0]);
}
else {
} else {
System.out.println("RemoteServer for JavaFXLibrary will be started at default port of: " + port + ".\n" +
"If you wish to use another port, restart the library and give port number\n" +
"as an argument.");
Expand All @@ -294,4 +313,3 @@ public static void main(String[] args) throws Exception {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public class ApplicationLauncher extends TestFxAdapter {
+ "Example:\n"
+ "| Launch JavaFX Application | _javafxlibrary.testapps.MenuApp_ |\n"
+ "| Launch JavaFX Application | _TestApplication.jar_ |\n")
@ArgumentNames({"appName", "*args"})
public void launchJavafxApplication(String appName, String... appArgs) {
@ArgumentNames({ "appName", "*args" })
public void launchJavafxApplication(String appName, String... appArgs) {
try {
RobotLog.info("Starting application:" + appName);
createNewSession(appName, appArgs);
Expand All @@ -65,7 +65,7 @@ public void launchJavafxApplication(String appName, String... appArgs) {
+ "Example:\n"
+ "| Launch Swing Application | _javafxlibrary.testapps.SwingApplication |\n"
+ "| Launch Swing Application | _TestApplication.jar_ |\n")
@ArgumentNames({"appName", "*args"})
@ArgumentNames({ "appName", "*args" })
public void launchSwingApplication(String appName, String... appArgs) {
RobotLog.info("Starting application:" + appName);
Class c = getMainClass(appName);
Expand All @@ -84,7 +84,7 @@ public void launchSwingApplication(String appName, String... appArgs) {
+ "Example:\n"
+ "| Launch Swing Application In Separate Thread | _javafxlibrary.testapps.SwingApplication |\n"
+ "| Launch Swing Application In Separate Thread | _TestApplication.jar_ |\n")
@ArgumentNames({"appName", "*args"})
@ArgumentNames({ "appName", "*args" })
public void launchSwingApplicationInSeparateThread(String appName, String... appArgs) {
RobotLog.info("Starting application:" + appName);
Class c = getMainClass(appName);
Expand All @@ -95,10 +95,11 @@ public void launchSwingApplicationInSeparateThread(String appName, String... app

private Class getMainClass(String appName) {
try {
if (appName.endsWith(".jar"))
if (appName.endsWith(".jar")) {
return getMainClassFromJarFile(appName);
else
} else {
return Class.forName(appName);
}
} catch (ClassNotFoundException e) {
throw new JavaFXLibraryNonFatalException("Unable to launch application: " + appName, e);
}
Expand All @@ -112,41 +113,43 @@ private void _addPathToClassPath(String path) {
try {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, (new File(path)).toURI().toURL() );
method.invoke(classLoader, (new File(path)).toURI().toURL());

} catch (Exception e) {
throw new JavaFXLibraryFatalException("Problem setting the classpath: " + path , e);
throw new JavaFXLibraryFatalException("Problem setting the classpath: " + path, e);
}
}

@RobotKeyword("Loads given path to classpath.\n\n"
+ "``path`` is the path to add.\n\n"
+ "If directory path has asterisk(*) after directory separator all jar files are added from directory.\n"
+ "\nExample:\n"
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder | \n"
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder${/}* | \n")
@ArgumentNames({"path"})
public void setToClasspath(String path) {
+ "``path`` is the path to add.\n\n"
+ "If directory path has asterisk(*) after directory separator all jar files are added from directory.\n"
+ "\nExample:\n"
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder | \n"
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder${/}* | \n")
@ArgumentNames({ "path" })
public void setToClasspath(String path) {
if (path.endsWith("*")) {
path = path.substring(0, path.length() - 1);
RobotLog.info("Adding all jars from directory: " + path);
path = path.substring(0, path.length() - 1);
RobotLog.info("Adding all jars from directory: " + path);

try {
File directory = new File(path);
File[] fileList = directory.listFiles();
boolean jarsFound = false;
for (File file : Objects.requireNonNull(fileList)) {
if (file.getName().endsWith(".jar")) {
jarsFound = true;
_addPathToClassPath(file.getAbsolutePath());
}
}
if(!jarsFound) throw new JavaFXLibraryNonFatalException("No jar files found from classpath: " + FileSystems.getDefault().getPath(path).normalize().toAbsolutePath().toString());
} catch (NullPointerException e) {
throw new JavaFXLibraryFatalException("Directory not found: " + path + "\n" + e.getMessage(), e);
}
}
else {
try {
File directory = new File(path);
File[] fileList = directory.listFiles();
boolean jarsFound = false;
for (File file : Objects.requireNonNull(fileList)) {
if (file.getName().endsWith(".jar")) {
jarsFound = true;
_addPathToClassPath(file.getAbsolutePath());
}
}
if (!jarsFound) {
throw new JavaFXLibraryNonFatalException("No jar files found from classpath: "
+ FileSystems.getDefault().getPath(path).normalize().toAbsolutePath().toString());
}
} catch (NullPointerException e) {
throw new JavaFXLibraryFatalException("Directory not found: " + path + "\n" + e.getMessage(), e);
}
} else {
_addPathToClassPath(path);
}
}
Expand All @@ -157,8 +160,9 @@ public void logApplicationClasspath() {
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
RobotLog.info("Printing out classpaths: \n");
for (URL url : urls)
for (URL url : urls) {
RobotLog.info(url.getFile());
}
} catch (Exception e) {
throw new JavaFXLibraryNonFatalException("Unable to log application classpaths", e);
}
Expand Down Expand Up @@ -237,7 +241,6 @@ public void clearObjectMap() {
objectMap.clear();
}


@RobotKeyword("Returns the class name of currently active JavaFX Application")
public String getCurrentApplication() {
try {
Expand All @@ -258,4 +261,9 @@ public String currentApplication() {
}
}

@RobotKeyword("Returns if JavaFXLibrary is started as java agent.")
public boolean isJavaAgent() {
return TestFxAdapter.isAgent;
}

}
Loading

0 comments on commit bcdf4c1

Please sign in to comment.