Say we have a Java Swing application, swingapp, running in one JVM. Is it possible to control swingapp from a Java application running in another JVM/process, e.g. like this:
ControlApp.java
process = startSwingAppInAnotherProcess();
JFrame frame = getSwingAppJFrame();
frame.visible(false) // hide swingapps JFrame
doAllKindsOfThingsWithJFrame(frame)..
killSwingApp(process);
The use case is GUI testing, where I want a generic solution that can start/stop any Swing app in an external process to isolate it from the test runner completely, but it should still be able to control the app via Swing manipulation.
If possible, concrete examples would be very much appreciated.
I think there are platform-dependent ways to send UI events to GUI elements in the same desktop; however I would better think of some standard interprocess communication.
You can try to start your applications in a certain port range and just make them search for each sibling and communicate between them by sockets. Or you can start a kind of parent daemon process in which every child registers itself (by sockets again), and then the parent communicates state changes to its children (something like a distributed version of Subject-Observer pattern)
One could use somewhat "higher" level sockets - ZeroMQ for this.
Here are client and server implementations:
You could start with a server to implement jframe.hide API call.
Note: if you don't like native C transport implementation, then you could just switch to
pure java version without additional changes to your code.
Related
I'm having some trouble writing a GUI in Java that can interact with Tcl scripts. When a Tcl script is run, I want information passed to this GUI and displayed. Further inputted information on the GUI should be able to be returned back to the script.
I'm currently using Tcl/Java. Unfortunately, I am using Teamcenter and according to the user manual, the Tk toolkit is not supported. So I'm trying to work with Swing again.
This is what I've tried to get to work for Swing, but nothing shows up when I run the script:
package require java
java::import javax.swing.JFrame
set window [java::new javax.swing.JFrame]
$window setSize 100 100
$window setVisible true
I've also found out about Swank, but there seems to be little documentation on it, so I'm not sure how to proceed.
Any advice on how to best approach this? Or where to find additional resources?
I'm not familiar with the Java libraries you mentioned, but judging from the
When a Tcl script is run, I want information passed to this GUI and displayed. Further inputted information on the GUI should be able to be returned back to the script.
statement your case is a perfect fit for IPC. I mean that I'd just start a Tcl program, connect your running Java and Tcl programs via some sort of IPC and then just do the exchange between them using an agreed-upon protocol.
The simplest cross-platform IPC might use TCP sockets: say, your Java application opens a socket on a random port listening on some loopback interface address and then passes the address of this socket to the Tcl application it spawns; the Tcl application then connects to that socket and both applications do exchange their commands and responses.
Another possibility is to communicate with the script using the standard IO channels of the Tcl shell hosting it — stdin and stdout: your Java host writes its commands to the spawned Tcl application's stdin and reads its output back from its stdout. This way is possibly simpler than a TCP socket but requires special handling on Windows (you have to run the script using tclsh, not wish as in the latter case it will have its standard channels connected to nowhere).
If you don't need cross-platform IPC and are okay to use external Tcl libraries, then you could communicate through platform-specific things like Unix-domain sockets, D-Bus, Windows named pipes (Unix named pipes can be used without extra packages), DDE etc.
Searching for background on what your problem might be, I found this thread on comp.lang.tcl which explains the problem. The issue is that you're not creating the GUI from the AWT Event Thread. To do that, you need to make a small Java class that implements Runnable (called Runner below) and which creates your GUI objects and shows them. This you can then instantiate and fire off through SwingUtilities.invokeLater via JTcl:
java::call javax.swing.SwingUtilities invokeLater [java::new Runner]
However, you're using JTcl which includes a package (hyde) that lets you put your Java code inside your Tcl code:
package require java
package require hyde
hyde::jclass Runner -package your.helper -implements Runnable {
public void run() {
your.Frame f = new your.Frame();
// ...
f.setVisible(true);
}
}
java::call javax.swing.SwingUtilities invokeLater [java::new your.helper.Runner]
It's just a shame that it isn't documented more clearly; it's easy to miss because it is located within the jtcllib documentation group.
Teamcenter doesn't support "external customizations".
I wrote the GUI in Java separately and ended up using Teamcenter's internal API to get the GUI to display.
My problem is pretty simple i have an application written in java and i want to send commands to it ex ( click a button , send some key strokes , click a menu item ) from my application witch i will write in delphi. Is this concept even possible ?
I actually had to do this at the last place I worked, you can get around it with complex window events etc... as mentioned above but if you have access to the Java source simply write other access methods either that call a specific runtime that closes (i.e. trigger a public static void main(String[] args); via a native call or via the command line.
OR
Implement simple a simple message system between Java/Delphi over TCP/IP and send either XML or some simple string mappings (I think it took about an hour to set up Maps that could pass back and forth).
In my case we were simply handling reporting and talking to the database so it was pretty easy to work around without getting into a native call. Alternatively, there is(was) a port of the JNI for Delphi that worked pretty well with Delphi 7. I have no clue what runtime you're using but it might be an option.
Honestly, the TCP/IP method is probably the easiest. It doesn't take a lot to implement, it doesn't eat a lot of resources and it allows you to execute "myMenuItem.onClick()" pretty easily as a packet, you just have to expose the methods.
http://home.pacifier.com/~mmead/jni/delphi/
Well It depends on which Java GUI technology is used . If SWT or AWT is used , you can get handle of UI components, because these two toolkit uses native libararies.. On the other hand, if that java application GUI is created by beans of SWING, you can not get any handle. Because, swing toolkit is implemented by pure Java..
If the Java app can be modified, the Java Robot API (included in JRE 1.3 and newer) might be helpful. This would allow to control a Swing application which does not provide windows handles as Gursel wrote. Obviously there would be some IPC required, which could be implemented using sockets for example.
The short: YES, but depending on the Java application, it might be difficult and unreliable.
I'm not a Java guy so I don't know if this is the norm, but the one Java application I had to automate displayed a single dialog that only used 1 (one) window handle! It was made up of several edit boxes, buttons, what looked like combo-boxes, but those were not true Windows controls but widgets re-created by whatever GUI toolkit the original developer used. I wasn't able to use normal Windows messages to manipulate those because, as far as Windows was concerned, it was a single window.
Happily the only thing I had to do was click a single button. I used mouse_event to move the mouse over the expected area for the button and then again to click the button. It works, but manipulating input this way is both unreliable and fragile.
To clarify Daniel Chapman and mjn comments, find below a code extract showing Delphi controlling a Java Swing UI component (TextField) contained in a Jframe based on NetBeans ClientEditor sample.
Please notice, that this example does not use the Java source code or use TCP, XML, Windowing events handling technics or IPC, it's just simply Delphi code calling some Java code.
procedure TForm1.Button1Click(Sender: TObject);
begin
FJFrame := Tjavax_swing_JFrame.Create('Client Editor');
FClientEditor := Tclienteditor_ClientEditor.Create;
FJFrame.GetContentPane().Add(FClientEditor);
FJFrame.Pack;
FJFrame.SetVisible(True);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Delphi setting a value in a Java Swing UI component
FclientEditor.FirstNameTextField.SetText('Delphi 1stName');
end;
The long type names are just as a matter of clarity for this example and can be shorter of course.Additionally there is no problem with JNI in this example.
Have you had a look at Java for Delphi?
It let's you call Java from Delphi exposing the Java types as Delphi types.
How can i gain control on window based appliaction in java.
I am not asking like world or Excel.
I am asking for a window based application, suppose a media player(not specific window media player) any media player that is running on window.
How would you control the windows based application if you took Java out of the equation?
Does the program provide a COM interface? There are a number of Java-COM
bridges.
Does the program provide a plug-in API? You could write the DLL in C/C++, then either use JNI/JNA to interact with the DLL from Java, or use some kind-of interprocess communications layer.
Do you have have some view in the to low level Win32 message pump of the program? Then perhaps you could create native DLL to send messages via SendMessage on behalf of the java program.
It really depends on what you expect to do with the program, and what the program provides. There is no built-in functionality allowing one program to control another program, especially from Java.
Is there a way to intercept the system keys in Java so that the events are not propagated to the operating system? Ctrl+Alt+Del or other security related combinations do not matter, the main problem is for example the Windows key.
The program in question is a for a full screen application that performs some remote operations via a proprietary protocol. Currently my only idea would be to solve this via JNI, whereas the solution for Windows seems to be simple, I'm not sure about Linux and MAC OS X.
I'd prefer a somewhat standard solution, maybe there is something for Java games or so.
Java processes the key strokes after the operating system (OS), so Java can't "intercept" them. Although, you could code OS specific stuff in C/C++ that intercepted the keystrokes and call it in Java using JNI.
This appears to be fixed in Java 5, so you could have a shot at it. Apparently, the KeyEvent class in the Java API exposes two Microsoft Windows keyboard specific events - VK_WINDOWS (for the left and right winkeys) and VK_CONTEXT_MENU (for the context menu key).
It is quite possible to trap these events by implementing a KeyListener, but be forewarned that if you attempt to capture the Winkey event alone, you're bound to trip the event handler of the OS first, before Java can process it.
I have a Java application which I want to shutdown 'nicely' when the user selects Start->Shutdown. I've tried using JVM shutdown listeners via Runtime.addShutdownHook(...) but this doesn't work as I can't use any UI elements from it.
I've also tried using the exit handler on my main application UI window but it has no way to pause or halt shutdown as far as I can tell. How can I handle shutdown nicely?
The previously mentioned JNI approach will likely work.
You can use JNA which is basically a wrapper around JNI to make it easier to use. An added bonus is that it (in my opinion at least) generally is faster and more maintainable than raw JNI. You can find JNA at https://jna.dev.java.net/
If you're just starting the application in the start menu because you're trying to make it behave like a service in windows, you can use the java service wrapper which is found here:
http://wrapper.tanukisoftware.org/doc/english/download.jsp
As far as I know you need to start using JNI to set up a message handler for the Windows WM_QUERYENDSESSION message.
To do this (if you're new to Windows programming like me) you'll need to create a new class of window with a new message handling function (as described here) and handle the WM_QUERYENDSESSION from the message handler.
NB: You'll need to use the JNIEnv::GetJavaVM(...) and then JavaVM::AttachCurrentThread(...) on the message handling thread before you can call any Java methods from your native message handling code.