Perhaps the most difficult aspect of Matlab-Java integration is JMI (Java-to-Matlab Integration) over a remote connection, meaning a Java program that communicates with a separate Matlab process. Once again I welcome guest blogger Joshua Kaplan, who concludes his series of JMI-related articles with the awaited holy grail on this topic.
Remote control of Matlab
Last week I demonstrated using matlabcontrol to call Matlab from Java from within the Matlab application. Today I will explain how to control Matlab from a remote Java session. We will create a small Java program that allows us to launch and connect to Matlab, then send it eval commands and receive the results. While this example will involve creating a dedicated user interface, matlabcontrol can be integrated into any existing Java program without requiring any user interface.
matlabcontrol was originally created for controlling Matlab, not for performing computations. If your exclusive concern is to perform Matlab computations and use the results in Java, then check the Matlab Builder JA toolbox, which is made by MathWorks and is officially supported. Unfortunately this toolbox is quite expensive and does not enable interaction with a running Matlab session (it uses the non-GUI Matlab engine, much as the compiler does). It is for this purpose that the open-source (free) matlabcontrol package was created.
Note that matlabcontrol opens a new running Matlab session and does not connect to an already-running session. Matlab commands can then be invoked either interactively (in Matlab’s Command Window) or remotely (from Java). Debugging an already-open Matlab session can be done with jdb over a dedicated port, using an altogether different mechanism than matlabcontrol – this will be discussed in a future post.
Matlab has documented support for a COM interface (Windows) and process pipes (Unix/Mac) that allow remote communication from external applications. Unfortunately Java does not natively support COM, which is where matlabcontrol helps using its RMI approach. Interested readers can also try using a Java/COM bridge (JACOB or JCOM) as an alternative that would have the added benefits of enabling communication with an existing Matlab session and of MathWorks’ documented support.
A simple RemoteExample
Today’s RemoteExample demo is too long to paste into this post; instead you can download the source code, or a jar file that contains both the pre-compiled classes and matlabcontrol. To run this jar on Windows or Mac OS X you only need to double click on it (if you are running on Linux I’m sure you know what to do…). If you wish to download and compile the source file, remember that you will need the matlabcontrol jar referenced in your Java classpath.
Let’s dive in: The file begins with the mainline followed by default sizes and status messages. The user interface is then built using standard Swing components – there’s nothing special here, just some panels, panes, text fields, buttons, etc.
The interesting part begins when the RemoteMatlabProxyFactory object is created:
RemoteMatlabProxyFactory factory = new RemoteMatlabProxyFactory(); |
This Matlab-proxy factory object is used when the user clicks the “Connect” button:
factory.requestProxy(); |
This creates a RemoteMatlabProxy object. RemoteMatlabProxys must be created by a RemoteMatlabProxyFactory and cannot be directly constructed. When requestProxy() is called, matlabcontrol launches Matlab and connects to it using RMI. When the connection is established, a MatlabConnectionListener added to the factory will be notified using its connectionEstablished(RemoteMatlabProxy proxy) callback method. The RemoteMatlabProxy object passed into this method is now connected to Matlab.
While this example only deals with communicating with a single Matlab session, matlabcontrol can handle multiple remote sessions. Whenever a new session is established, connectionEstablished(RemoteMatlabProxy proxy) is invoked on each connection listener. When a connection is lost due to Matlab closing, or in very rare cases Matlab encountering extremely severe errors, connectionLost(RemoteMatlabProxy proxy) is called. Calling methods on this proxy will lead to exceptions being thrown, as it can no longer communicate with Matlab. The proxy is passed because this information is useful when controlling multiple sessions of Matlab simultaneously.
When the “Invoke” button is pressed, the command and number of return arguments is sent to Matlab. If the number of return arguments is 0, the command will still execute but nothing will be returned. If the number is positive but less than the total number of return arguments, then only up to that number of arguments will be returned. If the number of return arguments specified exceeds the actual amount of arguments returned, a Java exception will be thrown. By default the fields are populated to return the result of “sqrt(5)“. Press “Invoke” to see what happens. Change the number of return arguments to 0, and click “Invoke” again. Now change the number to 2 and try once more.
When the Java program closes, it also exits Matlab. This is accomplished by adding a WindowListener to the program, which detects the Java closure event. It is important to call Matlab’s exit command as opposed to eval(“exit”), because all other proxy methods block (pause) until completion but in the case of exiting Matlab no signal will ever be sent by Matlab to indicate it has closed.
Parsing Matlab’s return values
Our eval commands are being sent using RemoteMatlabProxy‘s returningEval(String command, int returnCount) method, whose return type is Object, because Matlab can return multiple return types. For example, the expression “sqrt(5)” will return an array of doubles, “pwd” will return a java.lang.String, and “whos” will return a complicated array of arrays with a variety of base types and Objects.
This is what occurs in Matlab R2009b, but not necessarily in past or future versions. You will have to experiment to find out what is being returned on your particular platform. The demo can help as it lists everything returned, including array contents. The demo contains the formatResult(Object result, int level) method which recursively goes through the object returned from Matlab and builds a description of what it contains. As discussed in my introductory post on matlabcontrol, Matlab functions will either return a base type, an array of base types, or a String. However, if we call a Java function inside the Matlab environment then any Java object might be returned. This isn’t actually that absurd of a situation; it might arise if you are trying to control the Matlab UI.
When returning Java objects from Matlab certain restrictions and limitations apply. First, the object must be Serializable because of the underlying use of RMI. In practice this isn’t a huge issue as a very large number of built-in Java classes are Serializable, and making your own classes Serializable is usually trivial.
The second limitation is that whatever class you send from the Matlab environment to your Java program must be defined in your Java program. For any standard built-in Java class this won’t cause issues. However, if you attempt to send over classes custom to Matlab then your Java program must have those classes in its classpath (in practice this means reference the jar file containing that class). For HG (or rather, UDD) classes, you can use the following Matlab function to create a Java class interface that can be used in your Java code to access the Matlab object, or access the jar file that contains that class as explained above:
% This will create a figure.java file in the current folder: myClassHandle = classhandle(handle(gcf)); myClassHandle.createJavaInterface(myClassHandle.name, pwd); % alternately, you can use myClassHandle.JavaInterfaces{1} % = 'com.mathworks.hg.Figure' in this particular case % i.e., in your java code import com.mathworks.hg.Figure |
(UDD will be described in much more detail in a future article that is currently being prepared)
The third caveat is that you will be returned a copy of the Java object. This means that if you have a Java array in Matlab, send it to your Java program and then insert an object into the array, the array in Matlab will not be affected. However, you can then send that array back to Matlab, so in practice this does not cause significant issues. None of these restrictions are applicable to matlabcontrol for local sessions.
Conclusion
Today we have shown how a dedicated Matlab session can be started from a Java application, which then communicates with that Matlab session using the matlabcontrol package. This concludes my series on matlabcontrol. Please check out the matlabcontrol website for more information, examples and updates. If you use matlabcontrol, filling out this survey so that I can improve it, would be greatly appreciated.
Since the past few articles were heavy on Matlab-Java topics, the next few articles will be devoted to undocumented pure-Matlab tips and tricks, starting next week with the topic of how to customize the default menubar and toolbar actions.
Hi,
First of all I would like to thank you and Yair for the excellent enlightenments.
Why isn’t is possible to have a server class that “talks” with existing Matlab application with JMI?
Does JMI must open a new Matlab process?
Tx,
Lior
@Lior – It is certainly possible for a server to run inside of Matlab and allow for a client to connect to it. However, matlabcontrol does not use this approach because it adds additional complexity (particularly when wishing to control multiple sessions of Matlab simultaneously). If you’d like to have this functionality feel free to add it, all of the source code is available at http://matlabcontrol.googlecode.com
Cheers
Thanks for your articles. I found them helpful.
Thanks again.
All the best. 🙂
Thanks for your articles. They are very intresting. I have a question. When i press the “Connect” button, a new Matlab session opens, but on the command line there is:
“??? No method ‘connectFromMatlab’ with matching signature found for class
‘matlabcontrol.MatlabConnector’.”. From this point, i can’t use the “invoke” button. I’m using Matlab R2009b.
Can you help me?
Thanks a lot.
@Perseas – The problem is being caused because somehow the matlabcontrol support jar is not ending up in the class path of your Matlab session. This is supposed to happen automatically when the Matlab session opens (using javaaddpath), and I have seen issues of this with much earlier versions of Matlab, but not R2009b. Do you by chance have any other versions of matlabcontrol on your non-dynamic class path? That could possibly cause the issue. Another is if you are running the code from some very unusual path location, perhaps networked storage. The code that determines where the matlabcontrol support code is actually living is rather complicated and I would not be surprised if there are a number of situations it does not properly handle.
I have the same issue as Perseas. I’m running Windows XP and I tried matlabcontrol with three different versions of Matlab (2004, 2008 and 2009b).
I tried to put the matlabcontrol jar file in c:\matlabcontrol-3.1.0.jar in order to be sure not to have any problem with the path… but nothing better came up…
I do not have any other versions of matlabcontrol on my non-dynamic class path (if you mean in Matlab)…
I am so desperate… Let me know if you have any (great) idea…
@Kalerzz – did you try placing the JAR file in your static Java path (edit(‘classpath.txt’)) and then restarting Matlab? sometimes this solves some issues with the dynamic Java classpath. I’m not sure it it will help, but it’s worth a try.
-Yair
@Yair – Yes I’ve tried to put the JAR file path in the static Java path, but I face the same problem… Nevertheless, thank you for your suggestion 🙂
Don’t hesitate if you have any other idea!
hello
I have the same problem. I want to call matlab from java.
I do not know which step to take first. I have read from various web and it really confusing me. Can anyone help to solve my problem.
thank you.
Hi,
great article & illustration of the functionality. Thank you very much! I do have one question. Although in Eclipse the code run without any problems when I try to run it from Javaws (JNLP) environment it produces following error. Any suggestion what is going wrong?
****
SEVERE: Support code location is specified by an unknown protocol: http
at matlabcontrol.Configuration.getSupportCodeLocation (Configuration.java:216)
at matlabcontrol.RemoteMatlabProxyFactory.(RemoteMatlabProxyFactory.java:141)
at matlabcontrol.RemoteMatlabProxyFactory.(RemoteMatlabProxyFactory.java:163)
…
Hi All,
One question, from eclipse I can run the program and MATLAB start but I got noting in matlab console. Does somebody got the same issue?
Thanks in advance!
@Pam, try to put a sleep command before sending the numbers to Matlab. It is possible, Eclipse sends the numbers, before Matlab starts up. It happened to me in NetBeans, and with the sleep (for 1 second) command, everything works fine!
Hi Persea, All,
I put a slepp command as sleep(10000) but i get the following
0Exception in thread “main” matlabcontrols.MatlabConnectionException: MATLAB proxy could not be created in the specified amount of time: 60000 milliseconds
at matlabcontrols.RemoteMatlabProxyFactory.getProxy(RemoteMatlabProxyFactory.java:371)
at matlabcontrols.RemoteMatlabProxyFactory.getProxy(RemoteMatlabProxyFactory.java:333)
at Hi.main(Hi.java:19)
any ideas?
thanks in advance!
@Pam – I suggest that you contact Joshua Kaplan or post a question on the MatlabControl webpage
@Pam. The programmer of matlabcontrol specified the “time out” at 60 seconds. When you write the command sleep(10000), the programm will be paused for 10 seconds. So, in this case, it would be better if you write sleep(1000), and try again!
Somebody for my problem????
@ Thanks Perseas!
Where should I put the command? before or after initialize the get.proxy?
Thanks in advance!
@Pam. After the initializing! You are going to create the proxy, sleep the programme for a second with sleep(1000), and after this, send the numbers!
hello again. I wrote a programme in NetBeans (java). I’m sending some numbers to Matlab and it returns me the results. After the execution of the programme, the task from Netbeans continues to run. Can you tell me if it is possible to kill the task using commands inside the programme? I tried to use the command proxy.eval(“exit”);. It terminates Matlab (with an exception. but it’s OK), but the task is still running! If i try to run again my programme, i will have another one task, and another one, etc
Thanks again for your help!
hey , this is exactly what i was looking for ! really gr8 work !! i am trying to work with the matlabcontrol library all the day long but it seems that i have a problem !! .. everytime i call matlab session it open the matlab and suddenly it hangs up in the first few moments of the inialization .. even the simple hello world example ! i changed the the timeout to 120 000 millisec but still no response ! i think i can’t establish a connection between java and matlab ! any help here ? i’ll be very grateful for help 🙂
os :xp 32b
matlab : tested on 2009a & 2010b
I tried to compile the source code of the example but it didn’t work , the matlab opens and hangs .. although the downloaded compiled jar works fine ! is there anything i may be missing in compiling ?!
thanks a lot 🙂
Hello. I am using version R2010a of MATLAB on a Mac (OS X 10.6). While the local examples in which java is invoked from within MATLAB all work fine, I cannot get the remote examples to work. MATLAB fails to start. For example, I launch RemoteExample.jar and then press “Connect”. Nothing happens, not even an error. In my own java code, calls to getProxy() timeout. Any advice would be greatly appreciated.
Thank you!
Hi,
I saw a point in this post which says”Debugging an already-open Matlab session can be done with jdb over a dedicated port” Can somebody please help me in doing this. I am now able to launch single matlab session when i execute RemoteExample. But every time I execute, a new matlab session will appear. But I want a single matlab session to handle every time i run RemoteExample.
Thanks in advance.
Regards
Naresh
Hey Naresh, have you found a solution for Debugging an already-open Matlab session can be done with jdb over a dedicated port?
@Misha and Naresh – debugging MATLAB via jdb is described here and here. I plan to post an article about this sometime in the coming months.
Hi,
Thanks a lot for your efforts! But I’ve got a problem;
In my netbeans 7.0 platform, I used the library wrapper wizard to connect to matlabcontrol.jar. I then created a java class and tried run the source file. I got errors which I believe concern my Java classpath as shown below;
matlabcontrol.RemoteMatlabProxy is not public in matlabcontrol; cannot be accessed from outside package
exception matlabcontrol.MatlabInvocationException is never thrown in body of corresponding try statement
—-
Please please just help me, i’m doing my final year project and the deadline, man… help!
thanks.
@Will – I suggest that you contact Josh Kaplan (author of matlabcontrol) directly or via the matlabcontrol webpage.
Hi!
I have a problem with Matlabcontrol. When I call multiple Matlab functions from Java while running only one application; one Matlab command window opens for every function I call. This leads to having 10+ command windows opened during a simulation and it makes everything very slow. Do you have any suggestions?
@David
I have not used matlabcontrol for a while, but recall you have an option when connecting to either create a new MATLAB instance or connect to an existing one. It sounds like you are electing to create a new one each time. It also sounds like your functions could share a static instance of the MATLAB engine.
Hi, I am taking an image as input from JAVA GUI and want to pass that image to matlab custom-function named as abc.m. Its prototype is
Its takes the image path in ‘R’ and intensity in ‘Intensity’ variable. But I am unable to call the function. I am adding the path before calling the function using
addpath
function of matlab from java and then
rmpath
after the calling of the function but matlab command window says:
Any help sooner will be much appreciated.
Thanks.