Using Attach API Outside Of JDK - api

I have a small application that uses the Attach API to modify some third party classes during runtime. Alas, I have run into a large problem: the Attach API only comes with the JDK. The necessary files I can copy from the JDK and add into my project, but the library responsible for this(attach.(dll|so)) I can't. This is because I would have to copy attach.lib from a resource inside jar, and put it in the JRE/lib directory.
An action that would not work if the user isn't root on a Linux machine, therefore losing compatibility to alot of users (as this app is supposed to run on a server, and most servers are Linux, and I can't be sure all are root)
I looked into all the classes responsible for the attach API (VirtualMachine, AttachProvider etc) but found no place where it is loading the library.
Is it possible to do this? I mean, can I use the Attach API outside of a JDK installation? If so, how?

You can do so by modifying java.library.path:
static void addToLibPath(String path) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
if (System.getProperty("java.library.path") != null) {
// If java.library.path is not empty, we will prepend our path
// Note that path.separator is ; on Windows and : on Unix-like,
// so we can't hard code it.
System.setProperty("java.library.path",
path + System.getProperty("path.separator")
+ System.getProperty("java.library.path"));
} else {
System.setProperty("java.library.path", path);
}
// Important: java.library.path is cached
// We will be using reflection to clear the cache
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
}
Call addToLibPath("path") will add "path" to java.library.path.
Please note that java.library.path is cached, and reflection is required to clear the cache.

As far as I know, you need to run the application looking to do the "attach" from within a JDK (not a JRE). By doing this, you don't need to worry about providing the Attach API or its dependencies - as they are all provided for and managed by the JDK. That said, you shouldn't have any "root" concerns with doing this - as you can extract and run/use a JDK as any user (it doesn't have to be installed / executed as "root"). That said, you'll just need to ensure that your program doing the attaching and the program being attached to are running as the same OS user as to not run into security restrictions.

Our experience is that there is no reliable way to use the attach API without a full JDK. This was particularly acute on Windows. You might get it to work, but you might want to look into plain old JMX instead.

Related

How to provide an HttpClient to ktor server from the outside to facilitate mocking external services?

I am trying to provide an HttpClient from the outside to my ktor server so that I can mock external services and write tests, however I get this exception when I run my test:
Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
io.ktor.server.application.DuplicatePluginException: Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
at app//io.ktor.server.application.ApplicationPluginKt.install(ApplicationPlugin.kt:112)
at app//com.example.plugins.HTTPKt.configureHTTP(HTTP.kt:13)
at app//com.example.ApplicationKt.module(Application.kt:14)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:39)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:38)
and thats a bit unexpected to me because I am not applying the Compression plugin twice as far as I can tell. If I run the server normally and manually call my endpoint with curl then it works as expected. What am I doing wrong?
I added a runnable sample project here with a failing test.
sample project
official ktor-documentation-sample project.
The problem is that you have the application.conf file and by default, the testApplication function tries to load modules which are enumerated there. Since you also explicitly load them in the application {} block the DuplicatePluginException occurs. To solve your problem you can explicitly load an empty configuration instead of the default one:
// ...
application {
module(client)
}
environment {
config = MapApplicationConfig()
}
// ...

Network calls not working in EXE distribution build of Compose for Desktop Application

I have used Ktor JVM Client for doing network calls in Compose for Desktop Application.
Network calls are working fine in Debug build means when I am just running the application it's working fine.
But when I create the EXE distribution file, by executing the packageExe task in Gradle, it's creating an EXE file. I have installed it on my machine. Then I am running the application and I am seeing that network calls are not working. I have checked internet is working properly.
Please provide a solution to fix this issue. Thanks in advance.
Your question doesn't leave any details about the failure type (compile error? runtime exception? Empty data? etc.).
But if I had to speculate based on such limited information, I'd guess it's probably this: https://github.com/JetBrains/compose-jb/issues/429
Specifically, when packaging, you need to specify which JVM modules you want to be packed into your distributable app, and likely you are missing your crypto module. Try something like this:
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
modules("jdk.crypto.ec")
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "untitled"
}
}
}

How can I test electron-builder auto-update flow?

I built an Electron app and I am now looking at how to distribute it.
I went with electron-builder to handle packaging etc.
For a bit of context, as a web developer, I am used to continuously deploy web apps on a web server but I have a hard time figuring out how to distribute a packaged one in Electron.
In electron-builder docs there is a brief mention about testing auto-update:
"Note that in order to develop/test UI/UX of updating without packaging the application you need to have a file named dev-app-update.yml in the root of your project, which matches your publish setting from electron-builder config (but in YAML format)"
But, it's rather vague...
So I actually have two questions:
1. How do I actually test the auto-update flow?
Do I need to actually publish a new version to trigger an update locally? Seems pretty unclear, it would be like developing against the production server.
2. Is it possible to have a fallback for unsigned code?
I don't have yet any certificate for code signing. So the OS/app will block the auto-update. But, I'd still want to tell the user that an update is available so they can go and download the app manually. Can I do that? (going back to point 1, I'd like to be able to test this flow)
I've just finished dealing with this. I also wanted to test against a non-production server and avoid having to package my app each time I iterated. To test downloads I had to sign my app, which slowed things down. But it sounds like you just need to check for updates. Which I think you can do as follows...
I created a dummy github repo, then created a a file dev-app-update.yml containing:
owner: <user or organization name>
repo: dev-auto-update-testing
provider: github
The path where this file is expected to be defaults to a place you can't access. Thankfully, you can override it like so:
if (isDev) {
// Useful for some dev/debugging tasks, but download can
// not be validated becuase dev app is not signed
autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml');
}
...that should be enough for your case -- since you don't need downloads.
If not, here are some other tips:
you can change the repo setting in your electron-builder config to point at your dummy repo then package your app. This will give you a packed, production build that points at your dummy repo -- this is how I did my download testing (though I have a cert, and signed my app)
you should be calling autoUpdate's checkForUpdates(), but if checkForUpdatesAndNotify() gives you a useful OS Notification then you should be able to set autoUpdater.autoDownload to false and end up with what you need.
Lastly, it sounds you could skip autoUpdater, since you won't be using the download feature anyway. Instead you could use github's releases api, assuming you use github to host your release. If not then your host should have something similar. Use that to check for updates then tell the user from within your App (could present them with a clickable URL too). If you want OS Notifications electron has a module for that.
We're using electron-updater with GitHub as a provider for auto-updates. Unfortunately, it breaks a lot and the electron-builder team doesn't support these issues well (1, 2, 3) (from my own experience, but you can find more examples on GitHub).
One way to test updates in dev mode:
Create a build of your app with an arbitrarily high version number
Create a public repo and publish the above build
Create a dev-app-update.yml next to your main entry point and configure it for the repo above (see)
In your main entry point:
import { autoUpdater } from "electron-updater";
...
if (process.env.NODE_ENV === "development") {
// Customize the test by toggling these lines
// autoUpdater.autoDownload = false
// autoUpdater.autoInstallOnAppQuit = false;
autoUpdater.checkForUpdates();
}
Then when running yarn dev you should see something like:
Checking for update
...
Found version 100.0.0 (url: <>.exe)
Downloading update from <>.exe
updaterCacheDirName is not specified in app-update.yml Was app build using at least electron-builder 20.34.0?
updater cache dir: C:\Users\<>\AppData\Local\Electron
New version 100.0.0 has been downloaded to C:\Users\<>\AppData\Local\Electron\pending\<>.exe
And it should install when you close the dev app.
This should give you some certainty but we still ran into issues in production. If you want to be sure, play through the full update flow with a test repo but packaged production apps just as you would do with the live one.

Yii CAssetManager.basePath is invalid on PHPUnit test

i have a problem to run test. My model use extension Yii mail and then i run test its fail with wrong assert path. Another test runs finaly (model dont use any extensions). Preloading is only log.
I had a similar error and I explicitly set the basePath in config/test.php.
'components'=>array(
...
'assetManager'=>array(
'basePath'=>dirname(__FILE__).'/../../assets',
)
)
Im solved problem
public function setUp(){
Yii::app()->assetManager->basePath = '../../asserts';
}
Im dont know why this error throw only in one model...
PhpUnit runs primary in CLI mode and therefore some of environmental variables are missing. Yii's AssetManager uses one of such variable to determine webroot and since the variable does not exist, it will either throw error or set up invalid assets path on first attempt.
In my opinion, this issue is (indirectly) caused by PHPUnit because it only supports CLI testing mode, which makes some things really more difficult to test than it would be in HTTP request mode. Some guys therefore wrote tools to run unit tests via standard web GUI with whole native HTTP environment (e.g. https://github.com/NSinopoli/VisualPHPUnit). Eventually, you may use HTTP clients like Selenium to run your tests as if clicking over the page (see http://phpunit.de/manual/3.7/en/selenium.html).
Nevertheless, it's a matter of subjective opinion - somebody may argue, that testing in CLI mode has advantages, some guys will hate it. But the fact is, that one has to bear in mind differences between HTTP and CLI mode.

JNI UnsatisfiedLinkError- how do I load libraries correctly?

I'm trying to work with the Java sample Database program from the CardScan SDK.
I am working with files located in Java/JNI and Java/Database. The program must be run with a 32 bit JRE. I was able to do so on a 64 bit machine by uninstalling Java and installing the 32 bit version, then re-adding the system path for Java. I can run the program and interface with a CardScan database file (.cdb) successfully by double clicking the SDKData.bat file, but when I open the source files for editing and edit the Java.library.path to include the required library (CRTK_JNI.dll), I get UnsatisfiedLinkErrors everywhere:
Exception in thread "main" java.lang.UnsatisfiedLinkError: sdkdata.CRTK.CRTK_Init([I)I
at sdkdata.CRTK.CRTK_Init(Native Method)
at sdkdata.CRTK.(CRTK.java:239)
at sdkdata.SDKData.(SDKData.java:97)
at sdkdata.SDKData.main(SDKData.java:643)
Java Result: 1
Presumably this is happening because the library is not loading properly.
What do I need to do to run and edit the program at full capacity (with all the native functions from CRTK_JNI in working order)?
Presumably this is happening because the library is not loading properly.
On the contrary. The library load is complete. You aren't getting that from a System.load()/loadLibrary() call, you are getting the error when calling your native method, the one that should have the signature:
package sdkdata;
public class CRTK
{
public native int CRTK_Init(int[]);
}
So it isn't there, or you have changed the signature without regenerating the .h and .c files, or you have manually mangled the declaration some other way.
Post your code.
To clarify, this Java sample program is officially unsupported by the CardScan API - it was a bad idea to try to use the API with an unsupported language relying solely on an experimental implementation. I ended up using one of the supported languages (Visual Basic) to work with the SDK; if anyone looking at this question happens to be struggling with using the CardScan API, here is my VB implementation on Github.