/*******************************************************************************
* Copyright (c) 2010-2013, Embraer S.A., Budapest University of Technology and Economics
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Rodrigo Rizzi Starr, Lincoln Nascimento - initial API and implementation
*******************************************************************************/
package br.com.embraer.massif.commandevaluation.client;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;
import br.com.embraer.massif.commandevaluation.base.MatlabRemoteInterface;
import br.com.embraer.massif.commandevaluation.exception.MatlabError;
import br.com.embraer.massif.commandevaluation.exception.MatlabOutputException;
import br.com.embraer.massif.commandevaluation.exception.MatlabPropertiesException;
import br.com.embraer.massif.commandevaluation.exception.MatlabRMIException;
import br.com.embraer.massif.commandevaluation.util.MatlabProviderProperties;
import br.com.embraer.massif.commandevaluation.util.ModelProviderUtil;
/**
* Class responsible for invoking the remote methods in the matlab RMI server
* to execute the eval and evals and retrieve its output
*
* @author ldnascim
*/
public class MatlabClient {
private static final String EVAL_EXECUTIONMODE = "eval";
private static final String FEVAL_EXECUTIONMODE = "feval";
/** Will receive the instance for the matlab remote server**/
private MatlabRemoteInterface matlabRemote;
/** Used to retrieve the properties (url/port) **/
private MatlabProviderProperties serverProperties;
private String hostAddress;
private int hostPort;
private String serviceName;
/**
* Default Constructor
* @param matlabVersion Matlab version, used as an identifier
* for which matlab server the client will
* connect to
* @throws MatlabPropertiesException
* @throws MatlabRMIException
*/
public MatlabClient(String matlabVersion, String matlabPid) throws MatlabPropertiesException, MatlabRMIException {
serverProperties = new MatlabProviderProperties();
configureAndConnect(matlabVersion, matlabPid);
}
/**
* Constructor
* @param matlabVersion Matlab version, used as an identifier
* for which matlab server the client will
* connect to
* @param configPath Configuration file path
* @throws MatlabPropertiesException
* @throws MatlabRMIException
*/
public MatlabClient(String matlabVersion, String matlabPid,
String configPath) throws MatlabPropertiesException, MatlabRMIException {
serverProperties = new MatlabProviderProperties(configPath);
configureAndConnect(matlabVersion, matlabPid);
}
/**
* Reads properties from configuration file and tries
* to connect to RMI server
* @param matlabVersion Matlab release version
* @param matlabPid Matlab process pid
* @throws MatlabPropertiesException
* @throws MatlabRMIException
*/
private void configureAndConnect(String matlabVersion, String matlabPid) throws MatlabPropertiesException, MatlabRMIException {
String lcMatlabVersion = matlabVersion.toLowerCase();
// try to retrieve host address
hostAddress = serverProperties.getProperty(MatlabProviderProperties.MATLAB_SERVER_ADDRESS);
if (hostAddress == null || hostAddress.isEmpty()) {
MatlabPropertiesException exception =
new MatlabPropertiesException(MatlabError.INVALID_PROPERTY_CONTENT_ERROR, null);
exception.set("Config file: ", serverProperties.getConfigPath());
exception.set("Host address: ", hostAddress);
throw exception;
}
// try to retrieve host port
String hostPortStr = serverProperties.getProperty(MatlabProviderProperties.MATLAB_SERVER_PORT);
try {
hostPort = Integer.valueOf(hostPortStr);
} catch (NumberFormatException e) {
MatlabPropertiesException exception =
new MatlabPropertiesException(MatlabError.INVALID_PROPERTY_CONTENT_ERROR, e);
exception.set("Config file: ", serverProperties.getConfigPath());
exception.set("Host port: ", hostPortStr);
throw exception;
}
// store service name based on matlab version and PID(process ID)
serviceName = MatlabProviderProperties.MATLAB_SERVER_DEFAULT_SERVICE_NAME;
if (!lcMatlabVersion.isEmpty())
{
serviceName = serviceName + lcMatlabVersion + matlabPid;
}
// connects to RMI server
connectRMI();
}
/**
* Constructor
* @param hostAddress Host address
* @param hostPort Host port
* @param serviceName service name
* @throws MatlabRMIException
*/
public MatlabClient(String hostAddress, int hostPort, String serviceName) throws MatlabRMIException {
this.hostAddress = hostAddress;
this.hostPort = hostPort;
this.serviceName = serviceName;
// connects to RMI server
connectRMI();
}
/**
* Connect to the matlab RMI server
* @throws MatlabRMIException
*/
private void connectRMI() throws MatlabRMIException {
Exception exception = null;
// create to find and bind RMI registry for matlab server
try {
Registry registry = LocateRegistry.getRegistry(hostPort);
matlabRemote = (MatlabRemoteInterface) registry.lookup(serviceName);
} catch (RemoteException e) {
exception = e;
} catch (NotBoundException e) {
exception = e;
}
// if exception occurred, thrown it
if (exception != null) {
MatlabRMIException rmiException =
new MatlabRMIException(MatlabError.CONNECTING_RMI_ERROR, exception);
rmiException.set("Host port", hostPort);
rmiException.set("Service name", matlabRemote);
throw rmiException;
}
}
/**
* Executes feval("function evaluation") command in the matlab RMI server
* and retrieves its output(if any is expected)
* @param name Function name
* @param inputArgs Array of objects containing the function inputs
* @param numberOfOutputs Number of outputs
* @return Array of objects containing the feval output
* @throws MatlabRMIException
* @throws MatlabOutputException
* @throws RemoteException
*/
public Object[] executeFeval(String name, Object[] inputArgs,
int numberOfOutputs) throws MatlabRMIException, MatlabOutputException {
Object[] returnOutput = null;
try {
returnOutput =
matlabRemote.executeFeval(name, inputArgs, numberOfOutputs);
} catch (RemoteException e) {
MatlabRMIException exception = prepareMatlabRMIException(FEVAL_EXECUTIONMODE, name, inputArgs,
numberOfOutputs, e);
throw exception;
}
return returnOutput;
}
private MatlabRMIException prepareMatlabRMIException(String executionMode, String command, Object[] inputArgs,
int numberOfOutputs, RemoteException e) {
MatlabRMIException exception = new MatlabRMIException(MatlabError.INVOKING_COMMAND_ON_MATLAB_ERROR, e);
exception.set("Type:", executionMode);
exception.set("Command:", command);
exception.set("Input arguments", ModelProviderUtil.convertArrayToString(inputArgs, ","));
exception.set("Number of output arguments", numberOfOutputs);
return exception;
}
/**
* Executes eval("evaluation") command in the matlab RMI server
* and retrieves its output(if any is expected)
* @param command Evaluation command to be executed
* @param numberOfOutputs Number of outputs
* @return Array of objects containing the eval output
* @throws MatlabRMIException
* @throws MatlabOutputException
* @throws RemoteException
*/
public Object[] executeEval(String command, int numberOfOutputs) throws MatlabRMIException, MatlabOutputException {
Object[] returnOutput = null;
try {
returnOutput =
matlabRemote.executeEval(command, numberOfOutputs);
} catch (RemoteException e) {
MatlabRMIException exception = prepareMatlabRMIException(EVAL_EXECUTIONMODE, command, new Object[0],
numberOfOutputs, e);
throw exception;
}
return returnOutput;
}
/**
* Retrieves the current loaded and opened models in matlab
* @return List of strings containing the names of the models
* @throws MatlabRMIException
* @throws MatlabOutputException
* @throws RemoteException
*/
public List<String> getOpenedModels() throws MatlabRMIException, MatlabOutputException {
List<String> openedModels = new ArrayList<String>();
String command = "find_system";
Object[] inputsArgs = new Object[2];
inputsArgs[0] = "SearchDepth";
inputsArgs[1] = 0;
// retrieves all loaded models
Object[] returnOutput = null;
try {
returnOutput =
matlabRemote.executeFeval(command, inputsArgs, 1);
} catch (RemoteException e1) {
MatlabRMIException exception = prepareMatlabRMIException(FEVAL_EXECUTIONMODE, command, inputsArgs, 1, e1);
throw exception;
}
if (returnOutput != null && returnOutput.length > 0 &&
returnOutput[0] != null) {
String[] modelNames = (String[]) returnOutput[0];
if (modelNames.length > 0) {
// retrieve if the models are really "opened"
for (int i = 0; i < modelNames.length; i++) {
// check if is visible
command = "get_param";
inputsArgs = new Object[2];
inputsArgs[0] = modelNames[i];
inputsArgs[1] = "Shown";
try {
returnOutput =
matlabRemote.executeFeval(command, inputsArgs, 1);
} catch (RemoteException e) {
MatlabRMIException exception = prepareMatlabRMIException(FEVAL_EXECUTIONMODE, command,
inputsArgs, 1, e);
throw exception;
}
if (returnOutput != null && returnOutput.length > 0
&& returnOutput[0] != null) {
String showStatus = (String) returnOutput[0];
showStatus = showStatus.toLowerCase();
// if status is "on" then the model is loaded and opened
if (showStatus.equals("on")) {
openedModels.add(modelNames[i]);
}
}
}
}
}
return openedModels;
}
}