I persisted.
I had previously figured out how to pass in event handlers:
import org.jeffmandel.websocketserver.*;
try
server = org.jeffmandel.websocketserver.Server();
catch exception
fprintf("%s", exception.message);
end
myServerObj = handle(server,'CallbackProperties');
%#function dispatchMessage
set(myServerObj, 'OnMessageCallback', @dispatchMessage);
I haven't confirmed this, but I think the import of my class causes the jar to get loaded into the standalone app, and the %#function causes dispatchMessage to get scanned for inclusion. To make the 'OnMessageCallback' work, you need several methods in the Server class:
public synchronized void addSocketListener(SocketListener listener) {
if (listeners.isEmpty()) {
listeners.add(listener);
}
}
public synchronized void removeSocketListener(SocketListener listener) {
listeners.remove(listener);
}
public synchronized void dispatchEvent(SocketEvent event) {
for (SocketListener listener : listeners) {
listener.onMessage(event);
}
}
public interface SocketListener extends EventListener {
void onMessage(SocketEvent event);
}
public class SocketEvent extends EventObject {
private String message;
private WebSocket conn;
public SocketEvent(WebSocket source, String message) {
super(source);
this.message = message;
this.conn = source;
}
public String getMessage() {
return this.message;
}
public WebSocket getConn() {
return this.conn;
}
}
So now I build the standalone:
compiler.build.standaloneApplication('doServer.m','AdditionalFiles',{'allstates.mat'});
This carps:
Warning: Your personal MATLAB preferences are set to use the version of Java that is installed on this system. Users of this application may not have the same version of Java installed on their system causing the application to fail. This preference setting has been removed.
>> version -java
'Java is not enabled'
Odd, but
$ java -version
openjdk version "21.0.8" 2025-07-15
and System.getProperty("java.version") reports 21.0.8, so I can live with having to make sure I've got the correct JRE in my Docker build.
I create two systemd files:
# /etc/systemd/system/websocketserver.socket
[Unit]
Description=Socket listener for websocketserver
PartOf=websocketserver.service
[Socket]
ListenStream=127.0.0.1:3000
Accept=false
[Install]
WantedBy=sockets.target
and
# /etc/systemd/system/websocketserver.service
[Unit]
Description=Starts the MATLAB Websocket Server
Requires=websocketserver.socket
After=network.target websocketserver.socket
[Service]
Type=oneshot
WorkingDirectory=/home/jeffemandel/MATLAB-Drive/dise_service
ExecStart=/home/jeffemandel/MATLAB-Drive/dise_service/server/doServer
Environment="LD_LIBRARY_PATH=/usr/local/MATLAB/R2025b/runtime/glnxa64:/usr/local/MATLAB/R2025b/bin/glnxa64:/usr/local/MATLAB/R2025b/sys/os/glnxa64:/usr/local/MATLAB/R2025b/extern/bin/glnxa64"
StandardInput=socket
TimeoutStopSec=10
StandardError=journal
StandardOutput=journal
User=jeffemandel
[Install]
WantedBy=multi-user.target
I enable and start :
sudo systemctl daemon-reload
sudo systemctl enable websocketserver.socket
sudo systemctl start websocketserver.socket
journalctl -u tyrusserver -f
Now when my client connects to port 3000, the .socket activates the oneshot service, which runs my standalone app. The app figures out that it has been called from a socket in the constructor :
import org.java_websocket.WebSocket;
public class Server {
private WebSocketServer matlabSocketServer;
private List<SocketListener> listeners = new ArrayList<>();
public Server() throws IOException {
Channel channel = System.inheritedChannel();
if (channel == null) {
int port = 3000;
matlabSocketServer = new WebSocketServer(new java.net.InetSocketAddress(port));
} else if (channel instanceof ServerSocketChannel) {
matlabSocketServer = new WebSocketServer((ServerSocketChannel) channel);
} else {
throw new IOException("No channel available");
}
matlabSocketServer.start();
}
}
Note that you can call the standalone app from the command line; useful for testing. The java library makes use of the Java_websocket library.
I'll consider putting the MATLAB code on File Exchange, and maybe even put the java code on Github if there's interest.
