How do I use JCEF with Intellij? - java

I've been trying to figure out if there is a way to use Chromium browser as the UI for a Java application. I found this IntelliJ page: https://jetbrains.org/intellij/sdk/docs/reference_guide/jcef.html The thing I can't figure out is how I actually use this in my project. My IntelliJ version is 2020.3 and it says that in 2020.2 JCEF was enabled by default. I however cannot figure out how I use JCEF in my project. I can't seem to find any clear documentation. When I try to import, for example, com.intellij it can't find the package.
Are there any tutorials or guides to integrate JCEF in my IntelliJ project?

You can run jetty server or use resource provider.
Example of resource provider:
https://medium.com/virtuslab/creating-intellij-plugin-with-webview-3b27c3f87aea
Also this example of abstract WebDialog explain how to pass data to fe:
https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/kotlin/com/icthh/xm/actions/WebDialog.kt
All magic in class BrowserPipe (WebDialog.kt file) on backend side, and same class in frontend class
https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/webapp/src/index.html
Next js file it's one more part of magic
<script src="http://registercallback/events.js"></script>
This js file does not exists, but be listen this request and return generated js code.
CefApp.getInstance().registerSchemeHandlerFactory("http", "registercallback", InjectJsHandlerFactory(inject()))
For more details pls look to this line of code in (WebDialog.kt file)
After all manipulation as result i have ability to write components in simple way:
FE: https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/webapp/src/app/settings/settings.component.ts
constructor(private zone: NgZone) {
let w: any = window;
w.messagePipe.subscribe('initData', (res) => {
console.info('initData', res);
zone.run(() => {
this.updateData(res);
});
});
w.messagePipe.post('componentReady', 'SettingsComponent ready')
}
BE: https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/kotlin/com/icthh/xm/actions/settings/SettingsDialog.kt
override fun callbacks(): List<BrowserCallback> {
val data = ArrayList(project.getSettings().envs.map { it.copy() })
this.data = data;
return listOf(
BrowserCallback("componentReady") {body, pipe ->
logger.info("Update ${body}")
pipe.post("initData", mapper.writeValueAsString(mapOf(
"updateModes" to updateModes,
"branches" to project.getRepository().getLocalBranches(),
"envs" to data,
)))
},
BrowserCallback("envsUpdated") {body, pipe ->
logger.info("envsUpdated ${body}")
val envs = mapper.readValue<List<EnvironmentSettings>>(body)
this.data = ArrayList(envs);
}
)
}

Related

Is Jmeter Beanshell support invoke function from Kotlin jar file

I have Kotlin class:
class Ping {
fun ping(from: String): String{
return "Hello $from"
}
}
I've built jar file from this class. and included it to Jmeter and invoked it in BeanShell Sampler:
Ping ping = new Ping();
ping.ping("Jmeter");
it appear error Error invoking bsh method: eval Sourced file: inline evaluation of: ``Ping ping = new Ping(); ping.ping("Jmeter");'' : Method Invocation ping.ping
but I tried to change parameter of the method from string to int it work fine.
Any solution for this problem?
Thank you!
I cannot reproduce your issue using:
JMeter 5.4.1
Kotlin 1.5 (I copied the following .jars to JMeter Classpath just in case)
kotlin-reflect.jar
kotlin-reflect-sources.jar
kotlin-stdlib.jar
kotlin-stdlib-jdk7.jar
kotlin-stdlib-jdk7-sources.jar
kotlin-stdlib-jdk8.jar
kotlin-stdlib-jdk8-sources.jar
kotlin-stdlib-sources.jar
kotlin-test.jar
kotlin-test-sources.jar
The following sample code:
Ping ping = new Ping();
log.info(ping.ping("Jmeter"));
So double check your .jar file and JMeter Classpath. It also worth trying to put your code inside try block like
try {
Ping ping = new Ping();
log.info(ping.ping("Jmeter"));
}
catch (Exception ex) {
log.error("Beanshell failure", ex);
}
this way you will get the root cause of the problem in jmeter.log file
Also be aware that starting from JMeter 3.1 it's recommended to use JSR223 Test Elements and Groovy language for scripting so maybe it worth considering migrating to Groovy, see Apache Groovy - Why and How You Should Use It article for more details, it might be the case you won't need any Kotlin code.

Importing java classes in Intellij Kotlin app

I am using IntelliJ for the first time to write a Kotlin program for windows.
I need to read a file so I used code from a sample site:
import java.io.File
import java.io.InputStream
fun main(args: Array<String>) {
val inputStream: InputStream = File("bezkoder.txt").inputStream()
val lineList = mutableListOf<String>()
inputStream.bufferedReader().useLines { lines -> lines.forEach { lineList.add(it)} }
lineList.forEach{println("> " + it)}
}
The thing is that it doesn't recognise the import for the java classes.
I guess it is something in my setup but I have no idea where to look and haven't managed to find an answer.
This is my SDK setup screen
You can't use Java SDK classes in the Kotlin/Native projects, only in Kotlin/JVM.
Please also make sure you have a valid JDK configuration in the project. See this answer for more details.
If you want to read a file in Kotlin Native, see CsvParser.kt example.

Missing resolveStrategy breaks DSL when executed from runnable jar

I'm using the Groovy Spreadsheet Builder within one of my Grails projects to export some data as Excel file.
Everything works great until I create a runnable jar (using gradle assemble) and use this.
I'm using the builder within a service like this:
class ExcelService {
...
void export(OutputStream outputStream) {
...
PoiSpreadsheetBuilder.create(outputStream).build {
apply ExcelStylesheet
...
}
}
...
}
When I try to export my data from the app started using the generated jar I will get the following MissingMethodException:
groovy.lang.MissingMethodException: No signature of method: my.package.ExcelService.apply() is applicable for argument types: (java.lang.Class)
The (Java) interface of SpreadsheetBuilder looks like this:
public interface SpreadsheetBuilder {
void build(#DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = WorkbookDefinition.class) #ClosureParams(value = FromString.class, options = "builders.dsl.spreadsheet.builder.api.WorkbookDefinition") Configurer<WorkbookDefinition> workbookDefinition);
}
While debugging the execution of the code and the jar I found the difference while stepping through invokeMethod() of ClosureMetaClass.
When closure.getResolveStrategy(); in the working version is called Closure.DELEGATE_FIRST will be returned. Debugging the jar, the result will be 0 so that the MissingMethodException will be thrown later due to the wrong resolve strategy.
For now I have no idea how to solve this problem.
What is/could be the reason for this behavior?
What can I do to solve this issue?
I'm using Grails 3.3.8 with Java OpenJDK 1.8.0_192.
If you don't need to support JDK 7, you could upgrade to Groovy Spreadsheet Builder 2.0.0.RC1 which is only JDK 8 compatible but appears to solve the problem.
#ClosureParams and #DelegatesTo are applicable to parameters of type groovy.lang.Closure. In this case, you have applied it to Configurer<WorkbookDefinition>.

Why Unity3d failed importing jar plugin?

I have a small Unity3d project to integrate JAR with it. My (simplified) java class in Android Studio library project is like below code:
package com.playsqreen.library.api;
... imports ...
public class PlaysreenAPI {
private static PlayscreenAPI _api;
private PlayscreenAPI(Activity activity) {
this.activity = activity;
}
// static method to create singleton
public static PlayscreenAPI build(Activity activity, String key) {
if (_api == null) {
// post processing something
// before returning instance of this class
_api = new PlayscreenAPI(activity);
}
return _api;
}
public String doEchoThis(String msg) {
return "ECHO: " + msg;
}
}
So from Android Studio, I generate my JAR and dump it into ../MyProject/Assets/Plugins/Android and from Unity IDE I can see something like below:
Then I create a C# script like below to load my java class:
void Start () {
_builder = new StringBuilder();
try
{
_builder.Append(">>> Step 1\n");
AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
if (activityClass != null)
{
_builder.Append(">>> Step 2\n");
AndroidJavaObject activity = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
if (activity != null)
{
_builder.Append(">>> Step 3\n");
AndroidJavaClass apiClass = new AndroidJavaClass("com.playsqreen.library.api.PlayscreenAPI");
if (apiClass != null)
{
_builder.Append(">>> Step 4\n");
object[] args = { activity, secretKey };
api = apiClass.CallStatic<AndroidJavaObject>("build", args);
}
}
}
}
catch (System.Exception e)
{
_builder.Append(e.StackTrace.ToString());
}
}
I print my StringBuilder in Text UI object in order for me to capture on which Step my code brakes, and it turns out after step 3. and my Text UI object prints:
java.lang.ClassNotFoundException:com.playsqreen.library.api.PlayscreenAPI and etc...
A thread I found here suggest me to use Java Decompiler to check if the java class really included in the Jar, from this site. And so I did, and the Java Decompiler shows my java class does exists (see below)
So I really stuck now. How can I load my java class from Unity? Please help.
Thanks.
After following lysergic-acid advice below, I includes the rest of jars that required by my custom jar, see below pic. And everything fine :)
You did not post the full error message you are getting at runtime. Also you did not mention which of your debug prints get printed, so i'll try to come up with a few different issues that you can check. Hopefully, one of these can assist in fixing the issue:
JAR name contains '.' (period character). Not sure how Unity interprets this (i've never used such a naming convention myself). Select the .JAR file in Unity and make sure that Unity marks it up as an Android plugin (should have "Android" selected in the plugin importer. I would also try to rename that to a name without any periods just to be on the safe side.
Wrong invocation of the Java method: in your example, the static method build in Java receives a single argument (Activity), but when you're calling it from Unity, you're passing an array of 2 arguments.
Missing dependencies: When your native Java code relies on other classes (e.g: from other libraries), in case you do not include these libraries with your .JAR file, your class will not be loaded at runtime and it will fail with cryptic errors such as NoClassDefFoundException. Make sure to include all dependencies as well.
**Shameless Promotion: ** I offer services to fix Android related issues in Unity. Check it out here, in case you're interested :)
Install newest JDK version and try again.

Jxbtrowser retrieve platform specific artefact at runtime

I'm writing an intelij plugin and would like to download the platform specific artefact at runtime.
I've loaded the platform specific jar into a class loader but the ChromiumExtractor cannot access the nested resources when prefixed with "/". So I can access the resource as "chromium-mac.zip" but the library cannot.
I've tried to unzip the nested zipped chromium artefact into the correct directory but this does not leading to a working solution. So now I've been trying to piece together the way the library extracts the artefact but it's rather tedious as the code is obfuscated.
Does the jxbrowser plugin have some support for retrieving the artefact at runtime. Could such support be added (jxbtrowser devs use SO for support questions etc, this is a message to them :D ) ?
Approach taken :
// inside intelij plugin . The plugin has the jxbrowser-6.6.jar
// and license.jar loaded into the classloader. the platform specific
// artefact will be retrieved manual).
val cl = URLClassLoader(arrayOf(URL("file://.../jxbrowser-mac-6.6.jar")), Browser::class.java.classLoader)
val backup = Thread.currentThread().contextClassLoader
try {
Thread.currentThread().contextClassLoader = cl
// can access like this
Thread.currentThread().contextClassLoader.getResource("chromium-mac.zip")
val ce = ChromiumExtractor.create()
// cannot access as resource is retrieved "/chromium-mac.zip" ?
ce.extract(BrowserPreferences.getChromiumDir())
browser = Browser()
} finally {
Thread.currentThread().contextClassLoader = backup
}
The following does the trick, The resource jar had to be in the same class loader as the client jar (as well as the license). It would be nice if JxBrowser added a helper for this that is capable of performing the download and initialising chromium, perhaps taking just a path for a persistent storage directory.
private fun initializeJxBrowser(): Browser {
if(ChromiumExtractor.create().shouldExtract(BrowserPreferences.getChromiumDir())) {
val cl = URLClassLoader(arrayOf(
URL("file:.../license.jar"),
URL("file:.../jxbrowser-mac-6.6.jar"),
URL("file:../jxbrowser-6.6.jar")
))
cl.loadClass("com.teamdev.jxbrowser.chromium.BrowserContext")
.getMethod("defaultContext")
.invoke(null)
}
return Browser()
}

Categories