blob: 68e7cf615465a171c10aa0c6ca662cba49254b7d [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2008 The University of York.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.epsilon.emc.simulink.engine;
import java.lang.reflect.Method;
import java.util.concurrent.Future;
import org.eclipse.epsilon.emc.simulink.exception.MatlabException;
import org.eclipse.epsilon.emc.simulink.util.MatlabEngineUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("unchecked")
public class MatlabEngine {
/** ENGINE STATIC METHODS */
private static final String CONNECT_MATLAB_METHOD = "connectMatlab";
private static final String CONNECT_MATLAB_ASYNC_METHOD = "connectMatlabAsync";
private static final String START_MATLAB_METHOD = "connectMatlab";
private static final String START_MATLAB_ASYNC_METHOD = "connectMatlabAsync";
private static final String FIND_MATLAB_METHOD = "connectMatlab";
private static final String FIND_MATLAB_ASYNC_METHOD = "connectMatlabAsync";
/** ENGINE METHODS */
private static final String GET_VARIABLE_METHOD = "getVariable";
private static final String GET_VARIABLE_ASYNC_METHOD = "getVariableAsync";
private static final String PUT_VARIABLE_METHOD = "putVariable";
private static final String PUT_VARIABLE_ASYNC_METHOD = "putVariableAsync";
private static final String EVAL_METHOD = "eval";
private static final String EVAL_ASYNC_METHOD = "evalAsync";
private static final String FEVAL_METHOD = "feval";
private static final String FEVAL_ASYNC_METHOD = "fevalAsync";
private static final String DISCONNECT_METHOD = "disconnect";
private static final String DISCONNECT_ASYNC_METHOD = "disconnectAsync";
private static final String QUIT_METHOD = "quit";
private static final String QUIT_ASYNC_METHOD = "quitAsync";
private static final String CLOSE_METHOD = "close";
private static final String RESULT = "result";
private static final String ASIGN = " = ";
private static final String PARAM_REGEX = "[?]";
/** MATHWOWRKS CLASS */
private static final String MATLAB_ENGINE_CLASS = "com.mathworks.engine.MatlabEngine";
/** ERRORS AND LOGS */
private static final String ERROR_INVALID_PARAMETER_NUMBER = "%d parameters were expected but %d were provided";
private static final Logger LOGGER = LoggerFactory.getLogger(MatlabEngine.class);
/** VARIABLES */
protected Object engine;
private static Class<?> engine_class;
/** METHODS */
protected Method getVariableMethod;
protected Method getVariableAsyncMethod;
protected Method putVariableMethod;
protected Method putVariableAsyncMethod;
protected Method evalMethod;
protected Method evalAsyncMethod;
protected Method fevalMethod;
protected Method fevalWithVariableOutputsMethod;
protected Method fevalAsyncMethod;
protected Method closeMethod;
protected Method quitMethod;
protected Method disconnectMethod;
public MatlabEngine(Class<?> matlabEngineClass) throws Exception {
try{
engine = matlabEngineClass.getMethod(CONNECT_MATLAB_METHOD).invoke(null);
} catch (Exception e) {
LOGGER.debug("retrying connection");
engine = matlabEngineClass.getMethod(CONNECT_MATLAB_METHOD).invoke(null);
}
}
public Object evalWithSetupAndResult(String setup, String cmd, Object... parameters) throws MatlabException {
eval(setup + (setup.endsWith(";") ? "" : ";") + RESULT + ASIGN + cmd, parameters);
return getVariable(RESULT);
}
public Object evalWithResult(String cmd) throws MatlabException {
eval(RESULT + ASIGN + cmd);
return getVariable(RESULT);
}
public Object evalWithResult(String cmd, Object... parameters) throws MatlabException {
eval(RESULT + ASIGN + cmd, parameters);
return getVariable(RESULT);
}
public void eval(String cmd, Object... parameters) throws MatlabException {
cmd = " " + cmd + " ";
String[] parts = cmd.split(PARAM_REGEX);
if (parts.length != parameters.length + 1) {
String error = String.format(ERROR_INVALID_PARAMETER_NUMBER, parts.length - 1, parameters.length);
throw new RuntimeException(error);
}
cmd = parts[0];
for (int i = 0; i < parameters.length; i++) {
cmd += String.valueOf(parameters[i]).replace("'", "''").replace("\n", "\\n") + parts[i + 1];
}
cmd = cmd.substring(1, cmd.length() - 1);
eval(cmd);
}
/** CLASS HELPERS */
public static boolean is(Object obj) {
return (getMatlabClass() == null) ? false : getMatlabClass().isInstance(obj);
}
protected static Class<?> getMatlabClass() {
if (engine_class == null) {
try {
engine_class = ClassLoader.getSystemClassLoader().loadClass(MATLAB_ENGINE_CLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return engine_class;
}
public MatlabEngine(Object engine) {
if (is(engine)) {
this.engine = engine;
}
}
/** CLASS METHODS */
public static MatlabEngine startMatlab() throws MatlabException {
try {
Method startMatlabMethod = engine_class.getMethod(START_MATLAB_METHOD);
Object returnedEngine = startMatlabMethod.invoke(null);
return new MatlabEngine(returnedEngine);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
public static MatlabEngine startMatlab(String[] options) throws MatlabException {
try {
Method startMatlabMethod = engine_class.getMethod(START_MATLAB_METHOD, String[].class);
Object returnedEngine = startMatlabMethod.invoke(null, options);
return new MatlabEngine(returnedEngine);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
public static String[] findMatlab() throws MatlabException {
try {
Method findMatlabMethod = engine_class.getMethod(FIND_MATLAB_METHOD);
return (String[]) findMatlabMethod.invoke(null);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
public static MatlabEngine connectMatlab() throws MatlabException {
try {
Method connectMatlabMethod = engine_class.getMethod(CONNECT_MATLAB_METHOD);
Object returnedEngine = connectMatlabMethod.invoke(null);
return new MatlabEngine(returnedEngine);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
public static MatlabEngine connectMatlab(String name) throws MatlabException {
try {
Method connectMatlabMethod = engine_class.getMethod(CONNECT_MATLAB_METHOD, String.class);
Object returnedEngine = connectMatlabMethod.invoke(null, name);
return new MatlabEngine(returnedEngine);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
// TODO continue with the asynchronous static class methods
/** OBJECT METHODS */
public void eval(String cmd) throws MatlabException {
if (evalMethod == null) {
try {
evalMethod = engine.getClass().getMethod(EVAL_METHOD, String.class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
LOGGER.debug(cmd);
evalMethod.invoke(engine, cmd);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
throw new MatlabException(e);
}
}
public Future<Void> evalAsync(String cmd) throws MatlabException {
if (evalAsyncMethod == null) {
try {
evalAsyncMethod = engine.getClass().getMethod(EVAL_ASYNC_METHOD, String.class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
return (Future<Void>) evalAsyncMethod.invoke(engine, cmd);
} catch (Exception e) {
throw new MatlabException(e);
}
}
public Object getVariable(String variable) throws MatlabException {
if (getVariableMethod == null) {
try {
getVariableMethod = engine.getClass().getMethod(GET_VARIABLE_METHOD, String.class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
return MatlabEngineUtil.parseMatlabEngineVariable(getVariableMethod.invoke(engine, variable));
} catch (Exception e) {
throw new MatlabException(e);
}
}
public Object feval(int numberOfOutputs, String function, Object...handles) throws MatlabException {
if (fevalWithVariableOutputsMethod == null) {
try {
fevalWithVariableOutputsMethod = engine.getClass().getMethod(FEVAL_METHOD, int.class, String.class, Object[].class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
Object res = fevalWithVariableOutputsMethod.invoke(engine, numberOfOutputs, function, handles);
if (res != null) {
return MatlabEngineUtil.parseMatlabEngineVariable(res);
}
return null;
} catch (Exception e) {
throw new MatlabException(e);
}
}
public Object feval(String function, Object... handles) throws MatlabException {
if (fevalMethod == null) {
try {
fevalMethod = engine.getClass().getMethod(FEVAL_METHOD, String.class, Object[].class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
Object res = fevalMethod.invoke(engine, function, handles);
if (res != null) {
return MatlabEngineUtil.parseMatlabEngineVariable(res);
}
} catch (Exception e) {
MatlabException e1 = new MatlabException(e);
// Some methods such as saveChanges have no returning value. If called
// with this function and fails with not finding the method or the method
// throwing an exception, try reducing the number of expected outputs
System.err.println("Trying to find alternative '" + function + "' method...");
if (e1.isMatchingSignatureError() || e1.isTooManyOutput()) {
System.err.println("Alternative found for '" + function + "' method");
return feval(0, function, handles);
} else {
System.err.println("No alternative found for '" + function + "' method");
throw e1;
}
}
return null;
}
/*
// FIXME
public <T> Future<T> getVariableAsync(String variable) throws MatlabException {
if (getVariableAsyncMethod == null) {
try {
getVariableAsyncMethod = engine.getClass().getMethod(GET_VARIABLE_ASYNC_METHOD, String.class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
Future<T> response = (Future<T>) getVariableAsyncMethod.invoke(engine, variable);
// TODO Parse into T
return (Future<T>) response;
} catch (Exception e) {
throw new MatlabException(e);
}
}*/
public void putVariable(String variableName, Object value) throws MatlabException {
if (putVariableMethod == null) {
try {
putVariableMethod = engine.getClass().getMethod(PUT_VARIABLE_METHOD, String.class, Object.class);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
putVariableMethod.invoke(engine, variableName, value);
} catch (Exception e) {
e.printStackTrace();
throw new MatlabException(e);
}
}
public void close() throws MatlabException {
if (closeMethod == null) {
try {
closeMethod = engine.getClass().getMethod(CLOSE_METHOD);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
closeMethod.invoke(engine);
} catch (Exception e) {
throw new MatlabException(e);
}
}
public void quit() throws MatlabException {
if (quitMethod == null) {
try {
quitMethod = engine.getClass().getMethod(QUIT_METHOD);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
quitMethod.invoke(engine);
} catch (Exception e) {
throw new MatlabException(e);
}
}
public void disconnect() throws MatlabException {
if (disconnectMethod == null) {
try {
disconnectMethod = engine.getClass().getMethod(DISCONNECT_METHOD);
} catch (Exception e) {
throw new MatlabException(e);
}
}
try {
disconnectMethod.invoke(engine);
} catch (Exception e) {
throw new MatlabException(e);
}
}
}