<|start_filename|>src/matlabcontrol/demo/DemoMain.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.awt.EventQueue;
import java.net.URL;
import java.net.URLClassLoader;

import javax.swing.WindowConstants;

public class DemoMain {
	public static void main(String[] args) {
		new DemoMain();
	}

	public DemoMain() {
		final int closeOperation = isRunningInsideMATLAB() ? WindowConstants.HIDE_ON_CLOSE : WindowConstants.EXIT_ON_CLOSE;
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				DemoFrame frame = new DemoFrame("matlabcontrol demo - Running Inside MATLAB", null);
				frame.setDefaultCloseOperation(closeOperation);
				frame.setVisible(true);
			}
		});
	}

	private static boolean isRunningInsideMATLAB() {
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		URL[] urls = ((URLClassLoader) cl).getURLs();
		for (URL url : urls) {
			if (url.toExternalForm().contains("matlab")) {
				return true;
			}
		}
		return false;
	}
}


<|start_filename|>test/matlabcontrol/GetAndSetTest.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import matlabcontrol.link.ArrayUtilsTest;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

/**
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@Category(MatlabRequired.Headless.class)
public class GetAndSetTest {
	private static MatlabProxy proxy;

	@BeforeClass
	public static void createProxy() throws MatlabConnectionException {
		MatlabProxyFactoryOptions.Builder builder = new MatlabProxyFactoryOptions.Builder();
		builder.setUsePreviouslyControlledSession(true);
		MatlabProxyFactory factory = new MatlabProxyFactory(builder.build());
		proxy = factory.getProxy();
	}

	@AfterClass
	public static void exitMatlab() throws MatlabInvocationException {
		if (proxy != null) {
			proxy.disconnect();
		}
	}

	@Before
	public void clear() throws MatlabInvocationException {
		proxy.eval("clear");
	}

	@Test
	public void testSetGet() throws MatlabInvocationException {
		testCaseSetGet(new boolean[]{true});
		testCaseSetGet(new boolean[]{false});

		testCaseSetGet(new double[]{1.5});

		testCaseSetGet("string");
	}

	private void testCaseSetGet(Object set) throws MatlabInvocationException {
		proxy.setVariable("a", set);
		Object get = proxy.getVariable("a");
		ArrayUtilsTest.assertArraysEqual(set, get);
	}
}


<|start_filename|>src/matlabcontrol/extensions/MatlabTypeConverter.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.extensions;

import java.io.Serializable;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxy.MatlabThreadCallable;
import matlabcontrol.MatlabProxy.MatlabThreadProxy;

/** 
 * Converts between MATLAB and Java types. Currently only supports numeric arrays.
 * <br><br>
 * This class is unconditionally thread-safe.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class MatlabTypeConverter {
	private final MatlabProxy _proxy;

	/**
	 * Constructs the converter.
	 * 
	 * @param proxy
	 */
	public MatlabTypeConverter(MatlabProxy proxy) {
		_proxy = proxy;
	}

	/**
	 * Retrieves the MATLAB numeric array with the variable name {@code arrayName}.
	 * 
	 * @param arrayName
	 * @return the retrieved numeric array
	 * @throws matlabcontrol.MatlabInvocationException if thrown by the proxy
	 */
	public MatlabNumericArray getNumericArray(String arrayName) throws MatlabInvocationException {
		ArrayInfo info = _proxy.invokeAndWait(new GetArrayCallable(arrayName));

		return new MatlabNumericArray(info.real, info.imaginary, info.lengths);
	}

	private static class GetArrayCallable implements MatlabThreadCallable<ArrayInfo>, Serializable {
		private static final long serialVersionUID = -1269094288040717603L;
		private final String _arrayName;

		public GetArrayCallable(String arrayName) {
			_arrayName = arrayName;
		}

		@Override
		public ArrayInfo call(MatlabThreadProxy proxy) throws MatlabInvocationException {
			//Retrieve real values
			Object realObject = proxy.returningEval("real(" + _arrayName + ");", 1)[0];
			double[] realValues = (double[]) realObject;

			//Retrieve imaginary values if present
			boolean isReal = ((boolean[]) proxy.returningEval("isreal(" + _arrayName + ");", 1)[0])[0];
			double[] imaginaryValues = null;
			if (!isReal) {
				Object imaginaryObject = proxy.returningEval("imag(" + _arrayName + ");", 1)[0];
				imaginaryValues = (double[]) imaginaryObject;
			}

			//Retrieve lengths of array
			double[] size = (double[]) proxy.returningEval("size(" + _arrayName + ");", 1)[0];
			int[] lengths = new int[size.length];
			for (int i = 0; i < size.length; i++) {
				lengths[i] = (int) size[i];
			}

			return new ArrayInfo(realValues, imaginaryValues, lengths);
		}
	}

	private static class ArrayInfo implements Serializable {
		private static final long serialVersionUID = 4464014916120235711L;
		private final double[] real, imaginary;
		private final int[] lengths;

		public ArrayInfo(double[] real, double[] imaginary, int[] lengths) {
			this.real = real;
			this.imaginary = imaginary;
			this.lengths = lengths;
		}
	}

	/**
	 * Stores the {@code array} in MATLAB with the variable name {@code arrayName}.
	 * 
	 * @param arrayName the variable name
	 * @param array
	 * @throws matlabcontrol.MatlabInvocationException if thrown by the proxy
	 */
	public void setNumericArray(String arrayName, MatlabNumericArray array) throws MatlabInvocationException {
		_proxy.invokeAndWait(new SetArrayCallable(arrayName, array));
	}

	private static class SetArrayCallable implements MatlabThreadCallable<Object>, Serializable {
		private static final long serialVersionUID = -7403498224028558628L;
		private final String _arrayName;
		private final double[] _realArray, _imaginaryArray;
		private final int[] _lengths;

		private SetArrayCallable(String arrayName, MatlabNumericArray array) {
			_arrayName = arrayName;
			_realArray = array.getRealLinearArray();
			_imaginaryArray = array.getImaginaryLinearArray();
			_lengths = array.getLengths();
		}

		@Override
		public Object call(MatlabThreadProxy proxy) throws MatlabInvocationException {
			//Store real array in the MATLAB environment
			String realArray = (String) proxy.returningEval("genvarname('" + _arrayName + "_real', who);", 1)[0];
			proxy.setVariable(realArray, _realArray);

			//If present, store the imaginary array in the MATLAB environment
			String imagArray = null;
			if (_imaginaryArray != null) {
				imagArray = (String) proxy.returningEval("genvarname('" + _arrayName + "_imag', who);", 1)[0];
				proxy.setVariable(imagArray, _imaginaryArray);
			}

			//Build a statement to eval
			// - If imaginary array exists, combine the real and imaginary arrays
			// - Set the proper dimension length metadata
			// - Store as arrayName
			StringBuilder evalStatement = new StringBuilder(_arrayName + " = reshape(" + realArray);
			if (_imaginaryArray != null) {
				evalStatement.append(" + " + imagArray + " * i");
			}
			for (int length : _lengths) {
				evalStatement.append(", " + length);
			}
			evalStatement.append(");");
			proxy.eval(evalStatement.toString());

			//Clear variables holding separate real and imaginary arrays
			proxy.eval("clear " + realArray + ";");
			proxy.eval("clear " + imagArray + ";");

			return null;
		}
	}

	/**
	 * Returns a brief description of this converter. The exact details of this representation are unspecified and are
	 * subject to change.
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "[" + this.getClass().getName() + " proxy=" + _proxy + "]";
	}
}


<|start_filename|>test/matlabcontrol/link/ArrayUtilsTest.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import org.junit.Assert;
import org.junit.ComparisonFailure;
import org.junit.Test;

public class ArrayUtilsTest {
	@Test
	public void testDeepCopyOnPrimitives() {
		byte[] bytes = new byte[]{1, 2, 3, 4, 5};
		byte[] bytesCopied = ArrayUtils.deepCopy(bytes);
		Assert.assertTrue(bytes != bytesCopied);
		Assert.assertArrayEquals(bytes, bytesCopied);

		short[] shorts = new short[]{1, 2, 3, 4, 5};
		short[] shortsCopied = ArrayUtils.deepCopy(shorts);
		Assert.assertTrue(shorts != shortsCopied);
		Assert.assertArrayEquals(shorts, shortsCopied);

		int[] ints = new int[]{1, 2, 3, 4, 5};
		int[] intsCopied = ArrayUtils.deepCopy(ints);
		Assert.assertTrue(ints != intsCopied);
		Assert.assertArrayEquals(ints, intsCopied);

		long[] longs = new long[]{1, 2, 3, 4, 5};
		long[] longsCopied = ArrayUtils.deepCopy(longs);
		Assert.assertTrue(longs != longsCopied);
		Assert.assertArrayEquals(longs, longsCopied);

		float[] floats = new float[]{1, 2, 3, 4, 5};
		float[] floatsCopied = ArrayUtils.deepCopy(floats);
		Assert.assertTrue(floats != floatsCopied);
		Assert.assertArrayEquals(floats, floatsCopied, 0.01f);

		double[] doubles = new double[]{1, 2, 3, 4, 5};
		double[] doublesCopied = ArrayUtils.deepCopy(doubles);
		Assert.assertTrue(doubles != doublesCopied);
		Assert.assertArrayEquals(doubles, doublesCopied, 0.01);

		boolean[] bools = new boolean[]{true, true, false, true};
		boolean[] boolsCopied = ArrayUtils.deepCopy(bools);
		Assert.assertTrue(bools != boolsCopied);
		Assert.assertArrayEquals(bools, boolsCopied);

		char[] chars = new char[]{1, 2, 3, 4, 5};
		char[] charsCopied = ArrayUtils.deepCopy(chars);
		Assert.assertTrue(chars != charsCopied);
		Assert.assertArrayEquals(chars, charsCopied);
	}

	public static void assertArraysEqual(Object expected, Object actual) {
		if (expected.getClass().isArray()) {
			if (!ArrayUtils.equals(expected, actual)) {
				throw new ComparisonFailure("test failed", toString(expected), toString(actual));
			}
		} else {
			if (!expected.equals(actual)) {
				throw new ComparisonFailure("test failed", toString(expected), toString(actual));
			}
		}
	}

	private static String toString(Object any) {
		return "class: " + any.getClass() + "\ntoString: " + any.toString();
	}
}


<|start_filename|>src/matlabcontrol/PermissiveSecurityManager.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.security.Permission;

/**
 * A {@code SecurityManager} that always permits an action to take place. By default a Java application has no
 * {@code SecurityManager} set (although Java applets do). This security manager acts as if there was no security
 * manager in place. matlabcontrol uses Remote Method Invocation (RMI) to communicate with MATLAB when it is used in an
 * application that is not running inside MATLAB. RMI requires a security manager be set in order to allow loading
 * classes that are defined in the other Java Virtual Machine, but not its own. This is for good reason, because
 * allowing arbitrary code to be loaded into an application has the potential for a security exploit. By default RMI
 * allows connections from any external machine unless otherwise configured (or blocked by a firewall). matlabcontrol
 * is configured to prohibit any external connections on the port it is using.
 * <br><br>
 * When matlabcontrol launches a session of MATLAB it installs this security manager so that MATLAB may load classes
 * defined in your application. matlabcontrol does not install this security manager in your program. Installing any
 * security manager will allow your application to receive objects from MATLAB that are of classes defined in MATLAB,
 * but not in your application. Using this security manager is convenient when your application does not need any
 * security beyond the default of having no security manager installed.
 * <br><br>
 * To install this security manager:
 * <pre>
 * {@code
 * System.setSecurityManager(new PermissiveSecurityManager());
 * }
 * </pre>
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class PermissiveSecurityManager extends SecurityManager {
	/**
	 * Always accepts permission request.
	 * 
	 * @param perm 
	 */
	@Override
	public void checkPermission(Permission perm) {}

	/**
	 * Always accepts permission request.
	 * 
	 * @param perm
	 * @param context 
	 */
	@Override
	public void checkPermission(Permission perm, Object context) {}
}


<|start_filename|>src/matlabcontrol/link/ArrayLinearizer.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import static matlabcontrol.link.ArrayUtils.*;

import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.link.MatlabType.MatlabTypeSetter;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class ArrayLinearizer {
	static MatlabTypeSetter getSetter(Object array) {
		return new MultidimensionalPrimitiveArraySetter(array);
	}

	private static class MultidimensionalPrimitiveArraySetter implements MatlabTypeSetter {
		private static final long serialVersionUID = 7871972881461753065L;
		private final Object _linearArray;
		private final int[] _lengths;

		public MultidimensionalPrimitiveArraySetter(Object multidimensionalArray) {
			_lengths = computeBoundingDimensions(multidimensionalArray);
			_linearArray = linearize(multidimensionalArray, _lengths);
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			ops.setVariable(variableName, this);

			StringBuilder command = new StringBuilder();
			if (_lengths.length == 1) {
				command.append(variableName + " = reshape(" + variableName + ".getLinearArray(), 1, " + _lengths[0] + ");");
			} else {
				command.append(variableName + " = reshape(" + variableName + ".getLinearArray()");
				for (int length : _lengths) {
					command.append(", " + length);
				}
				command.append(");");
			}

			ops.eval(command.toString());
		}

		@SuppressWarnings("unused")
		// called in MATLAB by the script above
		public Object getLinearArray() {
			return _linearArray;
		}
	}

	/**
	 * Creates a linearized version of the {@code array}.
	 * 
	 * @param array a multidimensional primitive array
	 * @param lengths the bounding lengths of the array
	 * @return linear array
	 */
	static Object linearize(Object array, int[] lengths) {
		if (array == null || !array.getClass().isArray()) {
			throw new RuntimeException("provided object is not an array");
		}

		//Base component type of the array
		Class<?> baseClass = getBaseComponentType(array.getClass());
		if (!baseClass.isPrimitive()) {
			throw new RuntimeException("array type is not a primitive, type: " + baseClass.getCanonicalName());
		}

		//Create linear array with size equal to that of the bounding lengths of the array
		int size = getNumberOfElements(lengths);
		Object linearArray = Array.newInstance(baseClass, size);

		//Fill linearArray with values from array
		@SuppressWarnings("rawtypes")
		ArrayFillOperation fillOperation = FILL_OPERATIONS.get(baseClass);
		linearize_internal(linearArray, array, fillOperation, lengths, 0, new int[lengths.length]);

		return linearArray;
	}

	/**
	 * Performs the linearization using recursion.
	 * 
	 * @param linearArray array to be filled
	 * @param srcArray source array
	 * @param fillOperation operation to read values from srcArray and write into linearArray
	 * @param lengths the lengths of the array for the initial array supplied before any recursion
	 * @param depth the level of recursion, initially {@code 0}
	 * @param indices must be the length of {@code lengths}
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	private static void linearize_internal(Object linearArray, Object srcArray, ArrayFillOperation fillOperation,
			int[] lengths, int depth, int[] indices) {
		//Base case - array holding non-array elements
		if (!srcArray.getClass().getComponentType().isArray()) {
			fillOperation.fill(linearArray, srcArray, indices, lengths);
		} else {
			int arrayLength = Array.getLength(srcArray);
			for (int i = 0; i < arrayLength; i++) {
				indices[depth] = i;
				linearize_internal(linearArray, Array.get(srcArray, i), fillOperation, lengths, depth + 1, indices);
			}
		}
	}

	private static final Map<Class<?>, ArrayFillOperation<?>> FILL_OPERATIONS;

	static {
		Map<Class<?>, ArrayFillOperation<?>> map = new HashMap<Class<?>, ArrayFillOperation<?>>();

		map.put(byte.class, new ByteArrayFillOperation());
		map.put(short.class, new ShortArrayFillOperation());
		map.put(int.class, new IntArrayFillOperation());
		map.put(long.class, new LongArrayFillOperation());
		map.put(float.class, new FloatArrayFillOperation());
		map.put(double.class, new DoubleArrayFillOperation());
		map.put(boolean.class, new BooleanArrayFillOperation());
		map.put(char.class, new CharArrayFillOperation());

		FILL_OPERATIONS = Collections.unmodifiableMap(map);
	}

	private static interface ArrayFillOperation<T> {
		public void fill(T dst, T src, int[] indices, int[] lengths);
	}

	private static class ByteArrayFillOperation implements ArrayFillOperation<byte[]> {
		@Override
		public void fill(byte[] dst, byte[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class ShortArrayFillOperation implements ArrayFillOperation<short[]> {
		@Override
		public void fill(short[] dst, short[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class IntArrayFillOperation implements ArrayFillOperation<int[]> {
		@Override
		public void fill(int[] dst, int[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class LongArrayFillOperation implements ArrayFillOperation<long[]> {
		@Override
		public void fill(long[] dst, long[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class FloatArrayFillOperation implements ArrayFillOperation<float[]> {
		@Override
		public void fill(float[] dst, float[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class DoubleArrayFillOperation implements ArrayFillOperation<double[]> {
		@Override
		public void fill(double[] dst, double[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class BooleanArrayFillOperation implements ArrayFillOperation<boolean[]> {
		@Override
		public void fill(boolean[] dst, boolean[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class CharArrayFillOperation implements ArrayFillOperation<char[]> {
		@Override
		public void fill(char[] dst, char[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabSingle.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * MATLAB {@code single} with real and imaginary components.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabSingle extends MatlabNumber<Float> {
	private static final Float DEFAULT = 0.0f;

	public MatlabSingle(float real, float imag) {
		super(DEFAULT, real, imag);
	}

	/**
	 * Returns the real value.
	 * 
	 * @return 
	 */
	public float toReal() {
		return _real;
	}

	/**
	 * Returns the imaginary value.
	 * 
	 * @return 
	 */
	public float toImaginary() {
		return _imag;
	}
}


<|start_filename|>src/matlabcontrol/MatlabOperations.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

/**
 * Operations which interact with a session of MATLAB.
 * <br><br>
 * <b>WARNING:</b> This interface is not intended to be implemented by users of matlabcontrol. Methods may be added to
 * this interface, and these additions will not be considered breaking binary compatability.
 * 
 * @since 4.1.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public interface MatlabOperations {
	/**
	 * Evaluates a command in MATLAB. This is equivalent to MATLAB's {@code eval('command')}.
	 * 
	 * @param command the command to be evaluated in MATLAB
	 * @throws MatlabInvocationException 
	 */
	public void eval(String command) throws MatlabInvocationException;

	/**
	 * Evaluates a command in MATLAB, returning the result. This is equivalent to MATLAB's {@code eval('command')}.
	 * <br><br>
	 * In order for the result of this command to be returned the number of arguments to be returned must be specified
	 * by {@code nargout}. This is equivalent in MATLAB to the number of variables placed on the left hand side of an
	 * expression. For example, in MATLAB the {@code inmem} function may be used with either 1, 2, or 3 return values
	 * each resulting in a different behavior:
	 * <pre>
	 * {@code
	 * M = inmem;
	 * [M, X] = inmem;
	 * [M, X, J] = inmem;
	 * }
	 * </pre>
	 * The returned {@code Object} array will be of length {@code nargout} with each return argument placed into the
	 * corresponding array position.
	 * <br><br>
	 * If the command cannot return the number of arguments specified by {@code nargout} then an exception will be
	 * thrown.
	 * 
	 * @param command the command to be evaluated in MATLAB
	 * @param nargout the number of arguments that will be returned from evaluating {@code command}
	 * @return result of MATLAB command, the length of the array will be {@code nargout}
	 * @throws MatlabInvocationException
	 */
	public Object[] returningEval(String command, int nargout) throws MatlabInvocationException;

	/**
	 * Calls a MATLAB function with the name {@code functionName}, returning the result. Arguments to the function may
	 * be provided as {@code args}, but are not required if the function needs no arguments.
	 * <br><br>
	 * The function arguments will be converted into MATLAB equivalents as appropriate. Importantly, this means that a
	 * {@code String} will be converted to a MATLAB {@code char} array, not a variable name.
	 * 
	 * @param functionName the name of the MATLAB function to call
	 * @param args the arguments to the function
	 * @throws MatlabInvocationException 
	 */
	public void feval(String functionName, Object... args) throws MatlabInvocationException;

	/**
	 * Calls a MATLAB function with the name {@code functionName}, returning the result. Arguments to the function may
	 * be provided as {@code args}, but are not required if the function needs no arguments.
	 * <br><br>
	 * The function arguments will be converted into MATLAB equivalents as appropriate. Importantly, this means that a
	 * {@code String} will be converted to a MATLAB {@code char} array, not a variable name.
	 * <br><br>
	 * In order for the result of this function to be returned the number of arguments to be returned must be specified
	 * by {@code nargout}. This is equivalent in MATLAB to the number of variables placed on the left hand side of an
	 * expression. For example, in MATLAB the {@code inmem} function may be used with either 1, 2, or 3 return values
	 * each resulting in a different behavior:
	 * <pre>
	 * {@code
	 * M = inmem;
	 * [M, X] = inmem;
	 * [M, X, J] = inmem;
	 * }
	 * </pre>
	 * The returned {@code Object} array will be of length {@code nargout} with each return argument placed into the
	 * corresponding array position.
	 * <br><br>
	 * If the function is not capable of returning the number of arguments specified by {@code nargout} then an
	 * exception will be thrown.
	 * 
	 * @param functionName the name of the MATLAB function to call
	 * @param nargout the number of arguments that will be returned by {@code functionName}
	 * @param args the arguments to the function
	 * @return result of MATLAB function, the length of the array will be {@code nargout}
	 * @throws MatlabInvocationException 
	 */
	public Object[] returningFeval(String functionName, int nargout, Object... args) throws MatlabInvocationException;

	/**
	 * Sets {@code variableName} to {@code value} in MATLAB, creating the variable if it does not yet exist.
	 * 
	 * @param variableName
	 * @param value
	 * @throws MatlabInvocationException
	 */
	public void setVariable(String variableName, Object value) throws MatlabInvocationException;

	/**
	 * Gets the value of {@code variableName} in MATLAB.
	 * 
	 * @param variableName
	 * @return value
	 * @throws MatlabInvocationException
	 */
	public Object getVariable(String variableName) throws MatlabInvocationException;
}


<|start_filename|>src/matlabcontrol/link/MatlabInt64.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * MATLAB {@code int64} with real and imaginary components.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabInt64 extends MatlabNumber<Long> {
	private static final Long DEFAULT = 0L;

	public MatlabInt64(long real, long imag) {
		super(DEFAULT, real, imag);
	}

	/**
	 * Returns the real value.
	 * 
	 * @return 
	 */
	public long toReal() {
		return _real;
	}

	/**
	 * Returns the imaginary value.
	 * 
	 * @return 
	 */
	public long toImaginary() {
		return _imag;
	}
}


<|start_filename|>src/matlabcontrol/MatlabProxyFactoryOptions.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.io.File;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicLong;

import matlabcontrol.MatlabProxyFactory.CopyPasteCallback;

/**
 * Options that configure how a factory operates. Use a {@link Builder} to create an instance of this class.
 * <br><br>
 * This class is unconditionally thread-safe.
 * 
 * @see MatlabProxyFactory#MatlabProxyFactory(matlabcontrol.MatlabProxyFactoryOptions) 
 * @since 4.0.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class MatlabProxyFactoryOptions {
	private final String _matlabLocation;
	private final File _startingDirectory;
	private final boolean _hidden;
	private final boolean _usePreviouslyControlled;
	private final boolean _osgiClassloaderFriendly;
	private final CopyPasteCallback _copyPasteCallback;
	private final long _proxyTimeout;
	private final String _logFile;
	private final Integer _jdbPort;
	private final String _licenseFile;
	private final boolean _useSingleCompThread;
	private final int _port;
	private final Writer _outputWriter;
	private final Writer _errorWriter;

	private MatlabProxyFactoryOptions(Builder options) {
		_matlabLocation = options._matlabLocation;
		_startingDirectory = options._startingDirectory;
		_hidden = options._hidden;
		_usePreviouslyControlled = options._usePreviouslyControlled;
		_osgiClassloaderFriendly = options._osgiClassloaderFriendly;
		_copyPasteCallback = options._copyPasteCallback;
		_proxyTimeout = options._proxyTimeout.get();
		_logFile = options._logFile;
		_jdbPort = options._jdbPort;
		_licenseFile = options._licenseFile;
		_useSingleCompThread = options._useSingleCompThread;
		_port = options._port;
		_outputWriter = options._outputWriter;
		_errorWriter = options._errorWriter;
	}

	String getMatlabLocation() {
		return _matlabLocation;
	}

	File getStartingDirectory() {
		return _startingDirectory;
	}

	boolean getHidden() {
		return _hidden;
	}

	boolean getOsgiClassloaderFriendly() {
		return _osgiClassloaderFriendly;
	}

	boolean getUsePreviouslyControlledSession() {
		return _usePreviouslyControlled;
	}

	CopyPasteCallback getCopyPasteCallback() {
		return _copyPasteCallback;
	}

	long getProxyTimeout() {
		return _proxyTimeout;
	}

	String getLogFile() {
		return _logFile;
	}

	Integer getJavaDebugger() {
		return _jdbPort;
	}

	String getLicenseFile() {
		return _licenseFile;
	}

	boolean getUseSingleComputationalThread() {
		return _useSingleCompThread;
	}

	int getPort() {
		return _port;
	}

	Writer getOutputWriter() {
		return _outputWriter;
	}

	Writer getErrorWriter() {
		return _errorWriter;
	}

	/**
	 * Creates instances of {@link MatlabProxyFactoryOptions}. Any and all of these properties may be left unset, if so
	 * then a default will be used. Depending on how the factory operates, not all properties may be used. Currently all
	 * properties are used only when running outside MATLAB, but future releases may add additional options.
	 * <br><br>
	 * Calls on this class may be chained together to easily create factory options. Example usage:
	 * <pre>
	 * {@code
	 * MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
	 *                                         .setHidden(true)
	 *                                         .setProxyTimeout(30000L)
	 *                                         .build();
	 * }
	 * </pre>
	 * This class is unconditionally thread-safe.
	 * 
	 * @since 4.0.0
	 * @author <a href="mailto:<EMAIL>"><NAME></a>
	 */
	public static class Builder {
		private volatile String _matlabLocation = null;
		private volatile File _startingDirectory = null;
		private volatile boolean _hidden = false;
		private volatile boolean _usePreviouslyControlled = false;
		private volatile boolean _osgiClassloaderFriendly = false;
		private volatile CopyPasteCallback _copyPasteCallback = null;
		private volatile String _logFile = null;
		private volatile Integer _jdbPort = null;
		private volatile String _licenseFile = null;
		private volatile boolean _useSingleCompThread = false;
		private volatile int _port = 2100;
		private volatile Writer _outputWriter = null;
		private volatile Writer _errorWriter = null;

		//Assigning to a long is not atomic, so use an AtomicLong so that a thread always sees an intended value
		private final AtomicLong _proxyTimeout = new AtomicLong(180000L);

		/**
		 * Sets the location of the MATLAB executable or script that will launch MATLAB. If the value set cannot be
		 * successfully used to launch MATLAB, an exception will be thrown when attempting to create a proxy.
		 * <br><br>
		 * The absolute path to the MATLAB executable can be determined by running MATLAB. On OS X or Linux, evaluate
		 * {@code [matlabroot '/bin/matlab']} in the Command Window. On Windows, evaluate
		 * {@code [matlabroot '/bin/matlab.exe']} in the Command Window. The location provided does not have to be an
		 * absolute path so long as the operating system can resolve the path.
		 * <br><br>
		 * <strong>Windows</strong><br>
		 * Locations relative to the following will be understood:
		 * <ul>
		 * <li>The current working directory</li>
		 * <li>The {@code Windows} directory only (no subdirectories are searched)</li>
		 * <li>The {@code Windows\System32} directory</li>
		 * <li>Directories listed in the {@code PATH} environment variable</li>
		 * <li>App Paths defined in the registry with key
		 *     {@code HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths}</li>
		 * </ul>
		 * By default on Windows, MATLAB adds itself to the {@code PATH} environment variable as well as places an
		 * App Path entry in the registry so that {@code matlab} can be used to launch MATLAB. If this property is not
		 * set, then the {@code PATH} environment variable or the App Path entry will be used.
		 * <br><br>
		 * <strong>OS X</strong><br>
		 * Locations relative to the following will be understood:
		 * <ul>
		 * <li>The current working directory</li>
		 * <li>Directories listed in the {@code PATH} environment variable</li>
		 * </ul>
		 * On OS X, MATLAB is installed in {@code /Applications/} as an application bundle. If this property is not set,
		 * the executable inside of the application bundle will be used.
		 * <br><br>
		 * <strong>Linux</strong><br>
		 * Locations relative to the following will be understood:
		 * <ul>
		 * <li>The current working directory</li>
		 * <li>Directories listed in the {@code PATH} environment variable</li>
		 * </ul>
		 * During the installation process on Linux, MATLAB can create a symbolic link named {@code matlab} that can be
		 * used to launch MATLAB. If this property is not set, this symbolic link will be used.
		 * 
		 * @param matlabLocation
		 */
		public final Builder setMatlabLocation(String matlabLocation) {
			_matlabLocation = matlabLocation;

			return this;
		}

		/**
		 * Sets the starting directory for MATLAB.
		 * 
		 * @param dir
		 * @throws NullPointerException if {@code dir} is {@code null}
		 * @throws IllegalArgumentException if {@code dir} does not exist or is not a directory 
		 */
		public final Builder setMatlabStartingDirectory(File dir) {
			if (dir == null) {
				throw new NullPointerException("dir may not be null");
			}

			if (!dir.exists()) {
				throw new IllegalArgumentException("dir specifies a directory that does not exist");
			}

			if (!dir.isDirectory()) {
				throw new IllegalArgumentException("dir does not specify a directory");
			}

			_startingDirectory = dir;

			return this;
		}

		/**
		 * Sets whether MATLAB should appear hidden. By default this property is set to {@code false}. If set to
		 * {@code true} then the splash screen will not be shown and:
		 * <br><br>
		 * <strong>Windows</strong><br>
		 * The MATLAB Command Window will appear fully minimized.
		 * <br><br>
		 * <strong>OS X</strong><br>
		 * MATLAB will be entirely hidden. The MATLAB session will terminate when the Java application terminates.
		 * <br><br>
		 * <strong>Linux</strong><br>
		 * MATLAB will be entirely hidden. The MATLAB session will terminate when the Java application terminates.
		 * 
		 * @param hidden 
		 */
		public final Builder setHidden(boolean hidden) {
			_hidden = hidden;

			return this;
		}

		/**
		 * Sets whether to have MATLAB log any output to the MATLAB Command Window (including crash reports) to the
		 * file specified by {@code logFile}. The validity of {@code logFile} is not checked by matlabcontrol. By
		 * default output is not logged.
		 * 
		 * @param logFile 
		 */
		public final Builder setLogFile(String logFile) {
			_logFile = logFile;

			return this;
		}

		/**
		 * Sets whether to enable use of the Java debugger on the MATLAB session using port {@code portnumber}. The
		 * {@code portnumber} may be in the range {@code 0-65535} so long as it is not reserved or otherwise in use. By
		 * default the Java debugger is not enabled.
		 * 
		 * @param portnumber 
		 * @throws IllegalArgumentException if {@code portnumber} is not in the range {@code 0-65535}
		 */
		public final Builder setJavaDebugger(int portnumber) {
			if (portnumber < 0 || portnumber > 65535) {
				throw new IllegalArgumentException("port number [" + portnumber + "] must be in the range 0-65535");
			}

			_jdbPort = portnumber;

			return this;
		}

		/**
		 * Sets the license file used by MATLAB. By default no license file is specified. On Linux and OS X
		 * {@code licenseFile} may have the form {@code port@host} or a colon-separated list of license filenames. On
		 * Windows {@code licenseFile} may have the form {@code port@host}. Setting this option causes the
		 * {@code LM_LICENSE_FILE} and {@code MLM_LICENSE_FILE} environment variables to be ignored. The validity of
		 * {@code licenseFile} is not checked by matlabcontrol. 
		 * 
		 * @param licenseFile 
		 */
		public final Builder setLicenseFile(String licenseFile) {
			_licenseFile = licenseFile;

			return this;
		}

		/**
		 * Sets whether the factory should attempt to create a proxy that is connected to a running session of MATLAB.
		 * By default this property is set to {@code false}.
		 * <br><br>
		 * When this property is {@code true} all options which configure MATLAB such as being hidden or logging are
		 * ignored. The only criterion used is whether a session of MATLAB is available for connection. In order for the
		 * factory to connect to the session of MATLAB, it must know about the session. This will be the case if a
		 * factory started the session of MATLAB and that factory was configured to use the same port as specified by
		 * {@link #setPort(int)} (or both are using the default port). The factory will only connect to a session that
		 * does not currently have a proxy controlling it from outside of MATLAB.
		 * <br><br>
		 * To determine if the proxy created is connected to an existing session of MATLAB call
		 * {@link MatlabProxy#isExistingSession()}. You may wish to clear MATLAB's environment using {@code clear}.
		 * Doing so will not in anyway interfere with matlabcontrol (including executing {@code clear java}).
		 * <br><br>
		 * If a running session of MATLAB previously loaded classes defined in the controlling application, issues
		 * can arise. If your application does send to MATLAB or retrieve from MATLAB custom
		 * {@link java.io.Serializable} or {@link java.rmi.Remote} classes then these issues do not apply.
		 * <br><br>
		 * MATLAB sessions launched by matlabcontrol are able to load classes defined in the controlling application.
		 * When an existing session of MATLAB is connected to by a newly controlling application it will now be able to
		 * load classes defined by the newly controlling application but not the previous one. Several problems may
		 * arise due to this behavior. If an attempt is made to use a class defined in a previously controlling session
		 * that was not loaded while the application was controlling MATLAB then it will fail with a
		 * {@code ClassNotFoundException} if it is not also defined in the newly controlling application. If the class
		 * is defined it will fail to load it if the serializable definition is not compatible. A similar issue is if
		 * the newly controlling application attempts to send to MATLAB an instance of a class that was also defined by
		 * the previously controlling application but the serializable definition is not compatible. These above issues
		 * can easily be encountered when developing an application while changing {@code Serializable} or
		 * {@code Remote} classes and using the same session of MATLAB repeatedly. This will particularly be the case if
		 * the classes do not define a {@code serialVersionUID}. If multiple instances of the same application do not
		 * vary in their definition of {@code Serializable} and {@code Remote} classes then connecting to a previously
		 * controlled session of MATLAB will not cause any issues in this regard.
		 * 
		 * @param usePreviouslyControlled 
		 */
		public final Builder setUsePreviouslyControlledSession(boolean usePreviouslyControlled) {
			_usePreviouslyControlled = usePreviouslyControlled;

			return this;
		}

		/**
		 * If this is set, then RMI will be initiated in a way
		 * that doesn't get bogged down by OSGi.
		 */
		public final Builder setOSGiClassloaderFriendly(boolean osgiClassloaderFriendly) {
			_osgiClassloaderFriendly = osgiClassloaderFriendly;

			return this;
		}

		/**
		 * If this is set, then the factory will pass some MATLAB code to the given callback,
		 * which should be pasted into the MATLAB command prompt to initiate the connection.
		 *
		 * This trumps every other property besides setProxyTimeout().
		 */
		public final Builder setCopyPasteCallback(CopyPasteCallback copyPasteCallback) {
			_copyPasteCallback = copyPasteCallback;

			return this;
		}

		/**
		 * Sets the amount of time in milliseconds to wait for a proxy to be created when requested via the blocking
		 * method {@link MatlabProxyFactory#getProxy()}. By default this property is set to {@code 180000} milliseconds.
		 * 
		 * @param timeout
		 * 
		 * @throws IllegalArgumentException if timeout is negative
		 */
		public final Builder setProxyTimeout(long timeout) {
			if (timeout < 0L) {
				throw new IllegalArgumentException("timeout [" + timeout + "] may not be negative");
			}

			_proxyTimeout.set(timeout);

			return this;
		}

		/**
		 * Sets whether to limit MATLAB to a single computational thread. By default this property is set to
		 * {@code false}.
		 * 
		 * @param useSingleCompThread 
		 */
		public final Builder setUseSingleComputationalThread(boolean useSingleCompThread) {
			_useSingleCompThread = useSingleCompThread;

			return this;
		}

		/**
		 * Sets the port matlabcontrol uses to communicate with MATLAB. By default port {@code 2100} is used. The port
		 * value may not be negative. It is recommended to be in the range of {@code 1024} to {@code 49151}, but this
		 * range is not enforced. The port should be otherwise unused; however, any number of {@link MatlabProxyFactory}
		 * instances (even those running in completely separate applications) may use the same port. A 
		 * {@code MatlabProxyFactory} will only be able to connect to a previously controlled running session that was
		 * started by a factory using the same {@code port}.
		 * 
		 * @param port
		 * @throws IllegalArgumentException if port is negative
		 */
		public final Builder setPort(int port) {
			if (port < 0) {
				throw new IllegalArgumentException("port [" + port + "] may not be negative");
			}

			_port = port;

			return this;
		}

		/**
		 * Sets the output writer where the standard output of the created matlab process is written to.
		 * This is only used when an actual process is spawned for the matlab proxy instance.
		 * 
		 * @param outputWriter
		 */
		public final Builder setOutputWriter(Writer outputWriter) {
			_outputWriter = outputWriter;

			return this;
		}

		/**
		 * Sets the error writer where the error output of the created matlab process is written to. 
		 * This is only used when an actual process is spawned for the matlab proxy instance.
		 * 
		 * @param errorWriter
		 */
		public final Builder setErrorWriter(Writer errorWriter) {
			_errorWriter = errorWriter;

			return this;
		}

		/**
		 * Builds a {@code MatlabProxyFactoryOptions} instance.
		 * 
		 * @return factory options
		 */
		public final MatlabProxyFactoryOptions build() {
			return new MatlabProxyFactoryOptions(this);
		}
	}

}


<|start_filename|>src/matlabcontrol/link/MatlabInt64Array.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.Arrays;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @param <T> {@code long} array type, ex. {@code long[]}, {@code long[][]}, {@code long[][][]}, ...
 */
public class MatlabInt64Array<T> extends MatlabNumberArray<long[], T> {
	MatlabInt64Array(long[] real, long[] imag, int[] lengths) {
		super(long[].class, real, imag, lengths);
	}

	public static <T> MatlabInt64Array<T> getInstance(T real, T imaginary) {
		return new MatlabInt64Array<T>(real, imaginary);
	}

	private MatlabInt64Array(T real, T imaginary) {
		super(long[].class, real, imaginary);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt64 getElementAtLinearIndex(int index) {
		return new MatlabInt64(_real[index], (_imag == null ? 0 : _imag[index]));
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws IllegalArgumentException {@inheritDoc}
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt64 getElementAtIndices(int row, int column, int... pages) {
		int linearIndex = getLinearIndex(row, column, pages);

		return new MatlabInt64(_real[linearIndex], (_imag == null ? 0 : _imag[linearIndex]));
	}

	@Override
	boolean equalsRealArray(long[] other) {
		return Arrays.equals(_real, other);
	}

	@Override
	boolean equalsImaginaryArray(long[] other) {
		return Arrays.equals(_imag, other);
	}

	@Override
	int hashReal() {
		return Arrays.hashCode(_real);
	}

	@Override
	int hashImaginary() {
		return Arrays.hashCode(_imag);
	}

	@Override
	boolean containsNonZero(long[] array) {
		boolean contained = false;

		for (long val : array) {
			if (val != 0L) {
				contained = true;
				break;
			}
		}

		return contained;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabNumber.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;

/**
 * Corresponds to a MATLAB number with real and imaginary components.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
abstract class MatlabNumber<T extends Number> extends MatlabType {
	final T _real;
	final T _imag;

	/**
	 * The default value for {@code T}.
	 */
	private final T _default;

	MatlabNumber(T defaultValue, T real, T imag) {
		_default = defaultValue;

		_real = real;
		_imag = imag;
	}

	/**
	 * Returns {@code true} if the imaginary value is equivalent to the default value for the numeric type,
	 * {@code false} otherwise. Equivalent to the MATLAB {@code isreal} function.
	 * 
	 * @return 
	 */
	public boolean isReal() {
		return _default.equals(_imag);
	}

	/**
	 * Returns a {@code String} representation of the number. If the number is real the String representation is
	 * <i>real</i>. If an imaginary component is present, the format is <code><i>real</i> + <i>imag</i>i</code> if the
	 * imaginary component is non-negative and <code><i>real</i> - <i>imag</i>i</code> if the imaginary component is
	 * negative.
	 * 
	 * @return
	 */
	@Override
	public String toString() {
		String fullStr;
		String realStr = _real.toString();

		if (this.isReal()) {
			fullStr = realStr;
		} else {
			String imagStr = _imag.toString();
			if (imagStr.startsWith("-")) {
				fullStr = realStr + " - " + imagStr.substring(1, imagStr.length()) + "i";
			} else {
				fullStr = realStr + " + " + imagStr + "i";
			}
		}

		return fullStr;
	}

	/**
	 * Returns {@code true} if and only if the other object is of the same class and its component real and imaginary
	 * parts are both equal. The definition of equality for the component parts is defined by the {@code equals(...)}
	 * method of the boxed numeric class of its components.
	 * 
	 * @param obj
	 * @return 
	 */
	@Override
	public boolean equals(Object obj) {
		boolean equal = false;

		if (obj != null && this.getClass().equals(obj.getClass())) {
			MatlabNumber<?> other = (MatlabNumber<?>) obj;
			equal = _real.equals(other._real) && _imag.equals(other._imag);
		}

		return equal;
	}

	/**
	 * Returns a hash code compatible with {@code equals(...)}.
	 * 
	 * @return 
	 */
	@Override
	public int hashCode() {
		int hash = 5;
		hash = 79 * hash + _real.hashCode();
		hash = 79 * hash + _imag.hashCode();

		return hash;
	}

	@Override
	MatlabTypeSetter getSetter() {
		return new MatlabNumberSetter(_real, _imag);
	}

	//This is very non-object oriented to have this here instead of each subclass, but it saves a lot of boilerplate
	private static class MatlabNumberSetter implements MatlabTypeSetter {
		private static final long serialVersionUID = -8427476815084218279L;
		private final Number _real;
		private final Number _imag;

		private MatlabNumberSetter(Number real, Number imag) {
			_real = real;
			_imag = imag;
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String name) throws MatlabInvocationException {
			//Avoids limitation that MATLAB cannot multiply an integer stored in a variable by i

			if (_real instanceof Byte) {
				ops.eval(name + "=int8(" + _real.byteValue() + "+" + _imag.byteValue() + "i);");
			} else if (_real instanceof Short) {
				ops.eval(name + "=int16(" + _real.shortValue() + "+" + _imag.shortValue() + "i);");
			} else if (_real instanceof Integer) {
				ops.eval(name + "=int32(" + _real.intValue() + "+" + _imag.intValue() + "i);");
			} else if (_real instanceof Long) {
				ops.eval(name + "=int64(" + _real.longValue() + "+" + _imag.longValue() + "i);");
			}

			// Set value through an array to avoid values being converted to MATLAB double

			else if (_real instanceof Float) {
				ops.setVariable(name, new float[]{_real.floatValue(), _imag.floatValue()});
				ops.eval(name + "=" + name + "(1)+" + name + "(2)*i;");
			} else if (_real instanceof Double) {
				ops.setVariable(name, new double[]{_real.doubleValue(), _imag.doubleValue()});
				ops.eval(name + "=" + name + "(1)+" + name + "(2)*i;");
			}
		}
	}

	static class MatlabNumberGetter implements MatlabTypeGetter<MatlabNumber<?>> {
		private static final long serialVersionUID = 1339080882185682568L;
		private Object _real;
		private Object _imag;
		private boolean _retrieved;

		@Override
		public MatlabNumber<?> retrieve() {
			if (!_retrieved) {
				throw new IllegalStateException("complex number has not been retrieved");
			}

			MatlabNumber<?> num;
			if (_real.getClass().equals(Byte.class)) {
				num = new MatlabInt8((Byte) _real, (Byte) _imag);
			} else if (_real.getClass().equals(Short.class)) {
				num = new MatlabInt16((Short) _real, (Short) _imag);
			} else if (_real.getClass().equals(Integer.class)) {
				num = new MatlabInt32((Integer) _real, (Integer) _imag);
			} else if (_real.getClass().equals(Long.class)) {
				num = new MatlabInt64((Long) _real, (Long) _imag);
			} else if (_real.getClass().equals(Float.class)) {
				num = new MatlabSingle((Float) _real, (Float) _imag);
			} else if (_real.getClass().equals(Double.class)) {
				num = new MatlabDouble((Double) _real, (Double) _imag);
			} else {
				throw new IllegalStateException("unsupported numeric type: " + _real.getClass().getCanonicalName());
			}

			return num;
		}

		@Override
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			String receiverName = (String) ops.returningEval("genvarname('complex_receiver_', who);", 1)[0];
			try {
				ops.setVariable(receiverName, this);
				ops.eval(receiverName + ".setReal(real(" + variableName + "));");
				ops.eval(receiverName + ".setImaginary(imag(" + variableName + "));");
			} finally {
				ops.eval("clear " + receiverName);
			}

			_retrieved = true;
		}

		/**
		 * Sets the real value. Only meant to be called from MATLAB. In order for MATLAB to pass in the number, this
		 * method must have {@code Object} as its parameter, not {@code Number}.
		 * 
		 * @param real 
		 */
		public void setReal(Object real) {
			_real = real;
		}

		/**
		 * Sets the imaginary value. Only meant to be called from MATLAB. In order for MATLAB to pass in the number,
		 * this method must have {@code Object} as its parameter, not {@code Number}.
		 * 
		 * @param imag 
		 */
		public void setImaginary(Object imag) {
			_imag = imag;
		}
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabReturns.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.Arrays;

/**
 * MATLAB return containers.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@SuppressWarnings("unchecked")
public final class MatlabReturns {
	private MatlabReturns() {}

	/**
	 * Hidden super class of all of the {@code Return}X classes. This class is hidden because it is not a valid return
	 * type from a method declared in an interface provided to {@link MatlabFunctionLinker} and there is no need for a
	 * user to make use of this class.
	 */
	static class ReturnN {
		private final Object[] _values;

		ReturnN(Object[] values) {
			_values = values;
		}

		Object get(int i) {
			return _values[i];
		}

		/**
		 * Returns a brief description of this container. The exact details of this representation are unspecified and
		 * are subject to change.
		 * 
		 * @return 
		 */
		@Override
		public String toString() {
			return "[" + this.getClass().getCanonicalName() +
					" size=" + _values.length + "," +
					" values=" + Arrays.toString(_values) + "]";
		}
	}

	/**
	 * Container for two MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 */
	public static class Return2<A, B> extends ReturnN {
		Return2(Object[] values) {
			super(values);
		}

		/**
		 * The first return argument.
		 * 
		 * @return 
		 */
		public A getFirst() {
			return (A) get(0);
		}

		/**
		 * The second return argument.
		 * 
		 * @return 
		 */
		public B getSecond() {
			return (B) get(1);
		}
	}

	/**
	 * Container for three MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 */
	public static class Return3<A, B, C> extends Return2<A, B> {
		Return3(Object[] values) {
			super(values);
		}

		/**
		 * The third return argument.
		 * 
		 * @return 
		 */
		public C getThird() {
			return (C) get(2);
		}
	}

	/**
	 * Container for four MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 */
	public static class Return4<A, B, C, D> extends Return3<A, B, C> {
		Return4(Object[] values) {
			super(values);
		}

		/**
		 * The fourth return argument.
		 * 
		 * @return 
		 */
		public D getFourth() {
			return (D) get(3);
		}
	}

	/**
	 * Container for five MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 * @param <E> fifth return type
	 */
	public static class Return5<A, B, C, D, E> extends Return4<A, B, C, D> {
		Return5(Object[] values) {
			super(values);
		}

		/**
		 * The fifth return argument.
		 * 
		 * @return 
		 */
		public E getFifth() {
			return (E) get(4);
		}
	}

	/**
	 * Container for six MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 * @param <E> fifth return type
	 * @param <F> sixth return type
	 */
	public static class Return6<A, B, C, D, E, F> extends Return5<A, B, C, D, E> {
		Return6(Object[] values) {
			super(values);
		}

		/**
		 * The sixth return argument.
		 * 
		 * @return 
		 */
		public F getSixth() {
			return (F) get(5);
		}
	}

	/**
	 * Container for seven MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 * @param <E> fifth return type
	 * @param <F> sixth return type
	 * @param <G> seventh return type
	 */
	public static class Return7<A, B, C, D, E, F, G> extends Return6<A, B, C, D, E, F> {
		Return7(Object[] values) {
			super(values);
		}

		/**
		 * The seventh return argument.
		 * 
		 * @return 
		 */
		public G getSeventh() {
			return (G) get(6);
		}
	}

	/**
	 * Container for eight MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 * @param <E> fifth return type
	 * @param <F> sixth return type
	 * @param <G> seventh return type
	 * @param <H> eight return type
	 */
	public static class Return8<A, B, C, D, E, F, G, H> extends Return7<A, B, C, D, E, F, G> {
		Return8(Object[] values) {
			super(values);
		}

		/**
		 * The eight return argument.
		 * 
		 * @return 
		 */
		public H getEighth() {
			return (H) get(7);
		}
	}

	/**
	 * Container for nine MATLAB return values.
	 * 
	 * @param <A> first return type
	 * @param <B> second return type
	 * @param <C> third return type
	 * @param <D> fourth return type
	 * @param <E> fifth return type
	 * @param <F> sixth return type
	 * @param <G> seventh return type
	 * @param <H> eight return type
	 * @param <I> ninth return type
	 */
	public static class Return9<A, B, C, D, E, F, G, H, I> extends Return8<A, B, C, D, E, F, G, H> {
		Return9(Object[] values) {
			super(values);
		}

		/**
		 * The ninth argument.
		 * 
		 * @return 
		 */
		public I getNinth() {
			return (I) get(8);
		}
	}

	@SuppressWarnings("rawtypes")
	static ReturnN getMaxReturn(Object[] values) {
		return new Return9(values);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabLogicalMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public abstract class MatlabLogicalMatrix<T> extends MatlabNonNumericMatrix<boolean[], T> {
	MatlabLogicalMatrix() {}

	public static <T> MatlabLogicalMatrix<T> getFull(T values) {
		return new MatlabLogicalFullMatrix<T>(values);
	}

	public static MatlabLogicalMatrix<boolean[][]> getSparse(int[] rowIndices, int[] colIndices, boolean[] values,
			int numRows, int numCols) {
		return new MatlabLogicalSparseMatrix(rowIndices, colIndices, values, numRows, numCols);
	}

	public abstract boolean getElementAtLinearIndex(int linearIndex);

	public abstract boolean getElementAtIndices(int row, int column);

	public abstract boolean getElementAtIndices(int row, int column, int page);

	public abstract boolean getElementAtIndices(int row, int column, int[] pages);
}


<|start_filename|>src/matlabcontrol/link/MatlabNumberArray.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.lang.reflect.Array;
import java.util.Arrays;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.link.ArrayMultidimensionalizer.PrimitiveArrayGetter;

/**
 * Acts as a MATLAB numeric array of any dimension. This representation is a copy of the MATLAB data, not a live view.
 * Retrieving large arrays from MATLAB can result in a {@link OutOfMemoryError}; if this occurs you may want to either
 * retrieve only part of the array from MATLAB or increase your Java Virtual Machine's heap size.
 * <br><br>
 * MATLAB numeric arrays of {@code int8}, {@code int16}, {@code int32}, {@code int64}, {@code single}, and
 * {@code double} are supported by subclasses. They will become {@code byte}, {@code short}, {@code int}, {@code long},
 * {@code float}, and {@code double} Java arrays respectively. MATLAB unsigned integer values ({@code uint8},
 * {@code uint16}, {@code uint32}, and {@code uint64}) are not supported.
 * <br><br>
 * Arrays in MATLAB are stored in a linear manner. The number and lengths of the dimensions are stored separately from
 * the real and imaginary value entries. Each dimension has a fixed length. (MATLAB's array implementation is known as
 * a dope vector.)
 * <br><br>
 * Java has no multidimensional array type. To support multiple dimensions, Java allows for creating arrays of any data
 * type, including arrays. (Java's array implementation is known as an Iliffe vector.) A two dimensional array of
 * {@code double}s, {@code double[][]}, is just an array of {@code double[]}. A result of this is that each
 * {@code double[]} can have a different length. When not all inner arrays for a given dimension have the same length,
 * then the array is known as as a jagged array (also known as a ragged array).
 * <br><br>
 * MATLAB arrays are always two or more dimensions; single dimension Java arrays will become MATLAB arrays of length 1
 * by <i>n</i> where <i>n</i> is the length of the Java array.
 * <br><br>
 * When an array is retrieved from MATLAB the resulting Java array is never jagged. When a {@code MatlabNumberArray} is
 * constructed from Java arrays, the arrays provided may be jagged. The bounding "box" of the provided array or arrays
 * is used and 0 is placed in all MATLAB array locations which do not have a corresponding Java array location.
 * <br><br>
 * While this class mimics the dimension and lengths of a MATLAB array, it uses Java's zero-based indexing convention
 * instead of MATLAB's one-based convention. For instance in MATLAB if an array were indexed into as
 * {@code array(3,4,7,2)}, then in Java to retrieve the same entry the indexing would be performed as
 * {@code array[2][3][6][1]}.
 * <br><br>
 * Once constructed, this class is unconditionally thread-safe. If the data provided to a constructor is modified while
 * construction is occurring, problems may occur.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * 
 * @param <L> underlying linear array - single dimensional array type, ex. {@code byte[]}
 * @param <T> output array - primitive numeric array type, ex. {@code byte[][][]}
 *            (1 or more dimensions is acceptable, including for example {@code byte[]})
 */
@SuppressWarnings("unchecked")
abstract class MatlabNumberArray<L, T> extends MatlabType {
	/**
	 * The linear array of real values. Only intended to be accessed directly by subclasses inside this package.
	 */
	final L _real;

	/**
	 * The linear array of imaginary values. Can be {@code null} if this number array is real. Only intended to be
	 * accessed directly by subclasses inside this package.
	 */
	final L _imag;

	/**
	 * The length of the linear arrays. Of course, not applicable to the imaginary array if it is {@code null}.
	 */
	private final int _linearLength;

	/**
	 * The lengths of each dimension of the array when represented as an array of type {@code T}.
	 */
	private final int[] _dimensions;

	/**
	 * The primitive numeric type stored by the arrays.
	 */
	private final Class<?> _baseComponentType;

	/**
	 * Internal linear array type.
	 */
	private final Class<L> _linearArrayType;

	/**
	 * Output array type.
	 */
	private final Class<T> _outputArrayType;

	/**
	 * Caches the hash code.
	 * <br><br>
	 * To avoid any form of inter-thread communication this value may in the most degenerate case be recomputed for each
	 * thread.
	 */
	private Integer _hashCode = null;

	/**
	 * Caches if {@link #_imag} contains non-zero elements.
	 * <br><br>
	 * To avoid any form of inter-thread communication this value may in the most degenerate case be recomputed for each
	 * thread.
	 */
	private Boolean _hasImaginaryValues = null;

	/**
	 * Data from MATLAB. Provided as the linear arrays and dimensions.
	 * 
	 * @param linearArrayType
	 * @param realLinear
	 * @param imagLinear
	 * @param dimensions 
	 */
	MatlabNumberArray(Class<L> linearArrayType, L real, L imag, int[] dimensions) {
		//The real and imaginary arrays should always be of type L, but validate it
		_real = linearArrayType.cast(real);
		_imag = linearArrayType.cast(imag);

		//Linear and multidimensional dimensions
		_linearLength = Array.getLength(real);
		_dimensions = dimensions;

		//Make class information at run time
		_baseComponentType = linearArrayType.getComponentType();
		_linearArrayType = linearArrayType;
		_outputArrayType = (Class<T>) ArrayUtils.getArrayClass(_baseComponentType, dimensions.length);
	}

	/**
	 * Constructs a numeric array from Java arrays that can be transferred to MATLAB. The {@code imag} array
	 * may be {@code null}, if so then this array will be real. References to the arrays passed in are not kept, and
	 * modifying the array data after this class has been constructed will have no effect. If the data is modified
	 * concurrently with this class's construction, problems may arise.
	 * 
	 * @param linearArrayType the type of the linear array(s), ex. {@code byte[]}
	 * @param real may not be {@code null}
	 * @param imag may be {@code null}
	 * @throws NullPointerException if real array is null
	 * @throws IllegalArgumentException if the arguments are not arrays with the component type of
	 * {@code linearArrayType} or the two arrays are of different types
	 */
	MatlabNumberArray(Class<L> linearArrayType, T real, T imag) {
		//Real array cannot be null
		if (real == null) {
			throw new NullPointerException("Real array may not be null");
		}

		//Make class information available at run time
		_baseComponentType = linearArrayType.getComponentType();
		_linearArrayType = linearArrayType;
		_outputArrayType = (Class<T>) real.getClass();

		//Confirm real array is actually an array
		Class<?> realClass = real.getClass();
		if (!realClass.isArray()) {
			throw new IllegalArgumentException("Real array is not an array, type: " + realClass.getCanonicalName());
		}

		//Confirm the real array is of the supported type
		Class<?> realBaseComponentType = ArrayUtils.getBaseComponentType(realClass);
		if (!realBaseComponentType.equals(_baseComponentType)) {
			throw new IllegalArgumentException("Real array is not an array of the required class\n" +
					"Required base component type: " + _baseComponentType.getCanonicalName() + "\n" +
					"Provided base component type: " + realBaseComponentType.getCanonicalName());
		}

		//Confirm the imag array is of the same type as the real array
		if (imag != null && !imag.getClass().equals(realClass)) {
			throw new IllegalArgumentException("Imaginary array is not of the same class as the real array\n" +
					"Real array class: " + realClass.getCanonicalName() + "\n" +
					"Imaginary array class: " + imag.getClass().getCanonicalName());
		}

		//Determine dimensions
		_dimensions = new int[ArrayUtils.getNumberOfDimensions(_outputArrayType)];
		int[] realDimensions = ArrayUtils.computeBoundingDimensions(real);
		for (int i = 0; i < realDimensions.length; i++) {
			_dimensions[i] = Math.max(_dimensions[i], realDimensions[i]);
		}
		if (imag != null) {
			int[] imagDimensions = ArrayUtils.computeBoundingDimensions(imag);
			for (int i = 0; i < imagDimensions.length; i++) {
				_dimensions[i] = Math.max(_dimensions[i], imagDimensions[i]);
			}
		}

		//Linearize arrays
		_real = _linearArrayType.cast(ArrayLinearizer.linearize(real, _dimensions));
		if (imag != null) {
			_imag = _linearArrayType.cast(ArrayLinearizer.linearize(imag, _dimensions));
		} else {
			_imag = null;
			_hasImaginaryValues = false;
		}

		//Cache number of elements
		_linearLength = Array.getLength(_real);
	}

	/**
	 * Returns {@code true} if the array has no imaginary values, {@code false} otherwise. Equivalent to the MATLAB
	 * {@code isreal} function.
	 * 
	 * @return 
	 */
	public boolean isReal() {
		if (_hasImaginaryValues == null) {
			_hasImaginaryValues = containsNonZero(_imag);
		}

		return !_hasImaginaryValues;
	}

	abstract boolean containsNonZero(L array);

	/**
	 * Returns an array that holds the real values from the MATLAB array. Each call returns a new copy which may be used
	 * in any manner; modifications to it will have no effect on this instance.
	 * 
	 * @return real array
	 */
	public T toRealArray() {
		return _outputArrayType.cast(ArrayMultidimensionalizer.multidimensionalize(_real, _dimensions));
	}

	/**
	 * Returns an array that holds the imaginary values from the MATLAB array. Each call returns a new copy which may be
	 * used in any manner; modifications to it will have no effect on this instance. If this array is real then the
	 * returned array will be have {@code 0} as all of its base elements.
	 * 
	 * @return imaginary array
	 */
	public T toImaginaryArray() {
		T array;
		if (isReal()) {
			array = _outputArrayType.cast(Array.newInstance(_baseComponentType, _dimensions));
		} else {
			array = _outputArrayType.cast(ArrayMultidimensionalizer.multidimensionalize(_imag, _dimensions));
		}

		return array;
	}

	/**
	 * The number of elements in the array. The real and imaginary components of a number are together considered one
	 * element. This is equivalent to MATLAB's {@code numel} function.
	 * 
	 * @return number of elements
	 */
	public int getNumberOfElements() {
		return _linearLength;
	}

	/**
	 * Returns the length of the dimension specified by {@code dimension}. Dimensions use 0-based indexing. So the
	 * first dimension, which is dimension 0, is the row length. The second dimension is the column length. The third
	 * dimension and beyond are pages.
	 * 
	 * @param dimension
	 * @return length of {@code dimension}
	 * @throws IllegalArgumentException if {@code dimension} is not a dimension of the array
	 */
	public int getLengthOfDimension(int dimension) {
		if (dimension >= _dimensions.length || dimension < 0) {
			throw new IllegalArgumentException(dimension + " is not a dimension of this array. This array has " +
					getNumberOfDimensions() + " dimensions");
		}

		return _dimensions[dimension];
	}

	/**
	 * Returns the number of dimensions of the array.
	 * 
	 * @return number of dimensions
	 */
	public int getNumberOfDimensions() {
		return _dimensions.length;
	}

	/**
	 * Gets the element at {@code index} treating this array as a MATLAB column vector. This is equivalent to indexing
	 * into a MATLAB array with just one subscript.
	 * 
	 * @param index
	 * @return element at {@code index}
	 * @throws ArrayIndexOutOfBoundsException if {@code index} is out of bounds
	 */
	public abstract MatlabNumber<?> getElementAtLinearIndex(int index);

	/**
	 * Gets the element at the specified {@code row}, {@code column}, and {@code pages}.
	 * 
	 * @param row
	 * @param column
	 * @param pages
	 * @return element at {@code row}, {@code column}, and {@code pages}
	 * @throws IllegalArgumentException if number of indices does not equal this array's number of dimensions
	 * @throws ArrayIndexOutOfBoundsException if the indices are out of bound
	 */
	public abstract MatlabNumber<?> getElementAtIndices(int row, int column, int... pages);

	int getLinearIndex(int row, int column, int[] pages) {
		//Combine indices into one array
		int[] indices = new int[pages.length + 2];
		indices[0] = row;
		indices[1] = column;
		System.arraycopy(pages, 0, indices, 2, pages.length);

		if (indices.length == this.getNumberOfDimensions()) {
			//Check the indices are in bounds
			for (int i = 0; i < indices.length; i++) {
				if (indices[i] >= _dimensions[i]) {
					throw new ArrayIndexOutOfBoundsException("[" + indices[i] + "] is out of bounds for dimension " +
							i + " where the length is " + _dimensions[i]);
				}
			}
		} else {
			throw new IllegalArgumentException("Array has " + this.getNumberOfDimensions() + " dimension(s), it " +
					"cannot be indexed into using " + indices.length + " indices");
		}

		return ArrayUtils.multidimensionalIndicesToLinearIndex(_dimensions, indices);
	}

	/**
	 * Returns a brief description of this array. The exact details of this representation are unspecified and are
	 * subject to change.
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "[" + this.getClass().getName() +
				" type=" + _outputArrayType.getCanonicalName() + "," +
				" real=" + isReal() + ", " +
				" numberOfElements=" + this.getNumberOfElements() + "," +
				" numberOfDimensions=" + this.getNumberOfDimensions() + "," +
				" lengthsOfDimensions=" + Arrays.toString(_dimensions) + "]";
	}

	@Override
	public boolean equals(Object obj) {
		boolean equal = false;

		//Same object
		if (this == obj) {
			equal = true;
		}
		//Same class
		else if (obj != null && this.getClass().equals(obj.getClass())) {
			MatlabNumberArray<?, ?> other = (MatlabNumberArray<?, ?>) obj;

			//If the two instances are equal their hashcodes must be equal (but not the converse)
			if (this.hashCode() == other.hashCode()) {
				//Same dimensions (number and length)
				if (Arrays.equals(_dimensions, other._dimensions)) {
					//Both real values, or both complex values
					if ((this.isReal() && other.isReal()) || (!this.isReal() && !other.isReal())) {
						//Finally, compare the arrays
						equal = this.equalsRealArray((L) other._real) && this.equalsImaginaryArray((L) other._imag);
					}
				}
			}
		}

		return equal;
	}

	abstract boolean equalsRealArray(L other);

	abstract boolean equalsImaginaryArray(L other);

	@Override
	public int hashCode() {
		if (_hashCode == null) {
			int hashCode = 7;
			hashCode = 97 * hashCode + this.hashReal();
			hashCode = 97 * hashCode + this.hashImaginary();
			hashCode = 97 * hashCode + Arrays.hashCode(_dimensions);

			_hashCode = hashCode;
		}

		return _hashCode;
	}

	abstract int hashReal();

	abstract int hashImaginary();

	@Override
	MatlabTypeSetter getSetter() {
		return new MatlabNumberArraySetter(_real, _imag, _dimensions);
	}

	Class<T> getOutputArrayType() {
		return _outputArrayType;
	}

	private static class MatlabNumberArraySetter implements MatlabTypeSetter {
		private static final long serialVersionUID = -1170898489714890087L;
		private final Object _real;
		private final Object _imag;
		private final int[] _lengths;

		public MatlabNumberArraySetter(Object real, Object imag, int[] lengths) {
			_real = real;
			_imag = imag;
			_lengths = lengths;
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			ops.setVariable(variableName, this);

			StringBuilder command = new StringBuilder();
			command.append(variableName + " = reshape(" + variableName + ".getReal()");
			if (_imag != null) {
				command.append(" + " + variableName + ".getImaginary() * i");
			}

			if (_lengths.length == 1) {
				command.append(", 1, " + _lengths[0] + ");");
			} else {
				for (int length : _lengths) {
					command.append(", " + length);
				}
				command.append(");");
			}

			ops.eval(command.toString());
		}

		@SuppressWarnings("unused")
		// called in MATLAB by the script above
		public Object getReal() {
			return _real;
		}

		@SuppressWarnings("unused")
		// called in MATLAB by the script above
		public Object getImaginary() {
			return _imag;
		}
	}

	static class MatlabNumberArrayGetter implements MatlabTypeGetter<MatlabNumberArray<?, ?>> {
		private static final long serialVersionUID = 5757315814250115890L;
		private Object _real;
		private Object _imag;
		private int[] _lengths;
		private boolean _retreived = false;

		private final boolean _keepLinear;

		MatlabNumberArrayGetter(boolean keepLinear) {
			_keepLinear = keepLinear;
		}

		@Override
		public MatlabNumberArray<?, ?> retrieve() {
			if (!_retreived) {
				throw new IllegalStateException("array has not been retrieved");
			}

			//Create the appropriate subclass
			MatlabNumberArray<?, ?> array;
			if (_real.getClass().equals(byte[].class)) {
				array = new MatlabInt8Array<Object>((byte[]) _real, (byte[]) _imag, _lengths);
			} else if (_real.getClass().equals(short[].class)) {
				array = new MatlabInt16Array<Object>((short[]) _real, (short[]) _imag, _lengths);
			} else if (_real.getClass().equals(int[].class)) {
				array = new MatlabInt32Array<Object>((int[]) _real, (int[]) _imag, _lengths);
			} else if (_real.getClass().equals(long[].class)) {
				array = new MatlabInt64Array<Object>((long[]) _real, (long[]) _imag, _lengths);
			} else if (_real.getClass().equals(float[].class)) {
				array = new MatlabSingleArray<Object>((float[]) _real, (float[]) _imag, _lengths);
			} else if (_real.getClass().equals(double[].class)) {
				array = new MatlabDoubleArray<Object>((double[]) _real, (double[]) _imag, _lengths);
			} else {
				throw new IllegalStateException("unsupported array type: " + _real.getClass().getCanonicalName());
			}

			return array;
		}

		@Override
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			PrimitiveArrayGetter realGetter = new PrimitiveArrayGetter(true, true);
			realGetter.getInMatlab(ops, variableName);
			_real = realGetter.retrieve();

			if (_keepLinear) {
				_lengths = new int[]{realGetter.getLengths()[1]};
			} else {
				_lengths = realGetter.getLengths();
			}

			PrimitiveArrayGetter imagGetter = new PrimitiveArrayGetter(false, true);
			imagGetter.getInMatlab(ops, variableName);
			_imag = imagGetter.retrieve();

			_retreived = true;
		}
	}
}


<|start_filename|>src/matlabcontrol/extensions/MatlabNumericArray.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.extensions;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Acts as a MATLAB array of doubles. MATLAB arrays of any numeric type may be represented by a
 * {@code MatlabNumericArray}, but precision may be lost in the process. Dimensions of 2 and greater are supported. (No
 * array in MATLAB has a dimension less than 2.) This representation is a copy of the MATLAB data, not a live view.
 * Retrieving large arrays from MATLAB can result in a {@link OutOfMemoryError}; if this occurs you may want to either
 * retrieve only part of the array from MATLAB or increase your Java Virtual Machine's heap size.
 * <br><br>
 * <b>Note:</b> Sparse arrays are not supported. Attempts to retrieve a sparse may not throw an exception, but the
 * result will not be valid.
 * <br><br>
 * Both the real and imaginary components of a MATLAB array are supported. If the array has no imaginary values then
 * attempts to access these values will result in a {@link IllegalStateException} being thrown.
 * <br><br>
 * Arrays in MATLAB are stored in a linear manner. The number and lengths of the dimensions are stored separately from
 * the real and imaginary value entries. Each dimension has a fixed length. (MATLAB's array implementation is known as
 * a dope vector.)
 * <br><br>
 * Java has no multidimensional array type. To support multiple dimensions, Java allows for creating arrays of any data
 * type, including arrays. (Java's array implementation is known as an Iliffe vector.) A two dimensional array of
 * {@code double}s, {@code double[][]}, is just an array of {@code double[]}. A result of this is that each
 * {@code double[]} can have a different length. When not all inner arrays for a given dimension have the same length,
 * then the array is known as as a jagged array (also known as a ragged array).
 * <br><br>
 * When an array is retrieved from MATLAB the resulting Java array is never jagged. When a {@code MatlabNumericArray} is
 * constructed from Java arrays, the arrays provided may be jagged; see the
 * {@link #MatlabNumericArray(DoubleArrayType, java.lang.Object, java.lang.Object) main constructor} for details.
 * <br><br> 
 * Each instance knows the number of dimensions it represents and can create the corresponding multidimensional Java
 * array. In order to do this in a type safe manner the methods {@link #getRealArray(DoubleArrayType) getRealArray(...)}
 * and {@link #getImaginaryArray(DoubleArrayType) getImaginaryArray(...)} exist. Convenience methods exist to easily
 * retrieve the arrays as two, three, and four dimensional arrays. All of these methods will throw a
 * {@link ArrayDimensionException} if the array is not actually of that dimension. It is also possible to retrieve
 * values from the array without converting it to the corresponding multidimensional Java array. This can be done either
 * by using the index into the underlying linear MATLAB array, or by using the multidimensional indices. Retrieving
 * values in this manner does not require the computation and memory necessary to create the multidimensional Java
 * array.
 * <br><br>
 * While this class mimics the dimension and lengths of a MATLAB array, it uses Java's 0-index convention instead of
 * MATLAB's 1-index convention. For instance in MATLAB if an array were indexed into as {@code array(3,4,7,2)}, then in
 * Java to retrieve the same entry the indexing would be performed as {@code array[2][3][6][1]}.
 * <br><br>
 * Once constructed, this class is unconditionally thread-safe. If the data provided to a constructor is modified while
 * construction is occurring, problems may occur.
 * 
 * @see MatlabTypeConverter#setNumericArray(java.lang.String, matlabcontrol.extensions.MatlabNumericArray)
 * @see MatlabTypeConverter#getNumericArray(java.lang.String)
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabNumericArray {
	/**
	 * Linear array of real values.
	 */
	private final double[] _realValues;

	/**
	 * Linear array of imaginary values.
	 */
	private final double[] _imaginaryValues;

	/**
	 * The lengths for each dimension of the array.
	 */
	private final int[] _lengths;

	/**
	 * The type of double array.
	 */
	private final DoubleArrayType<?> _arrayType;

	/**
	 * If the array was retrieved from MATLAB.
	 */
	private final boolean _fromMatlab;

	/**
	 * If the array is composed entirely of real values. If this is {@code true} then {@link #_imaginaryValues} will be
	 * {@code null}.
	 */
	private final boolean _isReal;

	/**
	 * Constructs an array from data retrieved from MATLAB.
	 * 
	 * @param real
	 * @param imaginary
	 * @param lengths 
	 */
	MatlabNumericArray(double[] real, double[] imaginary, int[] lengths) {
		_fromMatlab = true;

		_realValues = real;
		_imaginaryValues = imaginary;
		_isReal = (imaginary == null);

		_lengths = lengths;
		_arrayType = DoubleArrayType.getInstance(lengths.length);
	}

	/**
	 * Constructs a numeric array from Java arrays that can be transferred to MATLAB. The {@code imaginary} array
	 * may be {@code null}, if so then this array will be real. References to the arrays passed in are not kept, and
	 * modifying the array data after this class has been constructed will have no effect. If the data is modified
	 * concurrently with this class's construction, problems may arise.
	 * <br><br>
	 * The arrays may be jagged; however, MATLAB does not support jagged arrays and therefore the arrays will be treated
	 * as if they had uniform length for each dimension. For each dimension the maximum length is determined. If both
	 * the {@code real} and {@code imaginary} arrays are provided then the maximum length per dimension is determined
	 * across both arrays. For parts of the array that have a length less than the maximum length, {@code 0} will be
	 * used.
	 * 
	 * @param <T>
	 * @param type may not be {@code null}
	 * @param real may not be {@code null}
	 * @param imaginary may be {@code null}, if {@code null} then this array will be real
	 * @throws NullPointerException
	 */
	public <T> MatlabNumericArray(DoubleArrayType<T> type, T real, T imaginary) {
		//Validate input
		if (type == null) {
			throw new NullPointerException("The type of the arrays may not be null.");
		}
		if (real == null) {
			throw new NullPointerException("Real array may not be null.");
		}

		_fromMatlab = false;
		_isReal = (imaginary == null);

		//Store type
		_arrayType = type;

		//Determine lengths
		_lengths = new int[type.getDimensions()];
		int[] realLengths = computeBoundingLengths(real);
		for (int i = 0; i < realLengths.length; i++) {
			_lengths[i] = Math.max(_lengths[i], realLengths[i]);
		}
		if (imaginary != null) {
			int[] imaginaryLengths = computeBoundingLengths(imaginary);
			for (int i = 0; i < imaginaryLengths.length; i++) {
				_lengths[i] = Math.max(_lengths[i], imaginaryLengths[i]);
			}
		}

		//Linearize arrays
		_realValues = linearize(real, _lengths);
		if (imaginary != null) {
			_imaginaryValues = linearize(imaginary, _lengths);
		} else {
			_imaginaryValues = null;
		}
	}

	/**
	 * Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_2, real, imaginary)}.
	 * 
	 * @param real
	 * @param imaginary 
	 * @throws NullPointerException
	 */
	public MatlabNumericArray(double[][] real, double[][] imaginary) {
		this(DoubleArrayType.DIM_2, real, imaginary);
	}

	/**
	 * Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_3, real, imaginary)}.
	 * 
	 * @param real
	 * @param imaginary 
	 * @throws NullPointerException
	 */
	public MatlabNumericArray(double[][][] real, double[][][] imaginary) {
		this(DoubleArrayType.DIM_3, real, imaginary);
	}

	/**
	 * Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_4, real, imaginary)}.
	 * 
	 * @param real
	 * @param imaginary 
	 * @throws NullPointerException
	 */
	public MatlabNumericArray(double[][][][] real, double[][][][] imaginary) {
		this(DoubleArrayType.DIM_4, real, imaginary);
	}

	/**
	 * Computes the total size of an array with lengths specified by {@code lengths}.
	 * 
	 * @param lengths
	 * @return 
	 */
	private static int getTotalSize(int[] lengths) {
		int size = 0;

		for (int length : lengths) {
			if (size == 0) {
				size = length;
			} else if (length != 0) {
				size *= length;
			}
		}

		return size;
	}

	/**
	 * Gets the real value at {@code linearIndex} treating this array as the underlying one dimensional array. This
	 * is equivalent to indexing into a MATLAB array with just one subscript.
	 * 
	 * @param linearIndex
	 * @return real value at {@code linearIndex}
	 * @throws ArrayIndexOutOfBoundsException
	 */
	public double getRealValue(int linearIndex) {
		return _realValues[linearIndex];
	}

	/**
	 * Gets the imaginary value at {@code linearIndex} treating this array as the underlying one dimensional array.
	 * This is equivalent to indexing into a MATLAB array with just one subscript.
	 * 
	 * @param linearIndex
	 * @return imaginary value at {@code linearIndex}
	 * @throws ArrayIndexOutOfBoundsException
	 * @throws IllegalStateException if the array is real
	 */
	public double getImaginaryValue(int linearIndex) {
		if (_isReal) {
			throw new IllegalStateException("array is real");
		}

		return _imaginaryValues[linearIndex];
	}

	/**
	 * Gets the real value at the specified {@code indices}. The amount of indices provided must be the number of
	 * dimensions in the array.
	 * 
	 * @param indices
	 * @return real value at {@code indices}
	 * @throws ArrayDimensionException if number of indices is not the number of dimensions
	 * @throws IndexOutOfBoundsException if the indices are out of bound
	 */
	public double getRealValue(int... indices) {
		return this.getValue(_realValues, indices);
	}

	/**
	 * Gets the imaginary value at the specified {@code indices}. The amount of indices provided must be the number of
	 * dimensions in the array.
	 * 
	 * @param indices
	 * @return imaginary value at {@code indices}
	 * @throws ArrayDimensionException if number of indices is not the number of dimensions
	 * @throws IndexOutOfBoundsException if the indices are out of bound
	 * @throws IllegalStateException if the array is real
	 */
	public double getImaginaryValue(int... indices) {
		if (_isReal) {
			throw new IllegalStateException("array is real");
		}

		return this.getValue(_imaginaryValues, indices);
	}

	private double getValue(double[] values, int... indices) throws ArrayDimensionException, ArrayIndexOutOfBoundsException {
		double value;
		if (indices.length == this.getDimensions()) {
			//Check the indices are in bounds
			for (int i = 0; i < indices.length; i++) {
				if (indices[i] >= _lengths[i]) {
					throw new IndexOutOfBoundsException("[" + indices[i] + "] is out of bounds for dimension " +
							i + " where the length is " + _lengths[i]);
				}
			}

			value = values[multidimensionalIndicesToLinearIndex(_lengths, indices)];
		} else {
			throw new ArrayDimensionException(_arrayType.getDimensions(), indices.length);
		}

		return value;
	}

	/**
	 * The number of dimensions this array has.
	 * 
	 * @return number of dimensions
	 */
	public int getDimensions() {
		return _arrayType.getDimensions();
	}

	/**
	 * Returns the lengths of each dimension with respect to their index. In MATLAB the first dimension (0 index in the
	 * returned integer array) is the row length. The second dimension is the column length. The third dimension and
	 * beyond are pages. The length of the returned array will be the number of dimensions returned by
	 * {@link #getDimensions()}.
	 * 
	 * @return lengths
	 */
	public int[] getLengths() {
		int[] lengthsCopy = new int[_lengths.length];
		System.arraycopy(_lengths, 0, lengthsCopy, 0, _lengths.length);

		return lengthsCopy;
	}

	/**
	 * The length of the underlying linear array.
	 * 
	 * @return length
	 */
	public int getLength() {
		return _realValues.length;
	}

	private <T> T getAsJavaArray(DoubleArrayType<T> type, double[] values) {
		if (type.getDimensions() != _arrayType.getDimensions()) {
			throw new ArrayDimensionException(_arrayType.getDimensions(), type.getDimensions());
		}

		return multidimensionalize(values, type._arrayClass, _lengths);
	}

	/**
	 * Returns a {@code double} array of type {@code T} that holds the real values from the MATLAB array.
	 * 
	 * @param <T>
	 * @param type
	 * @return 
	 * @throws ArrayDimensionException if the array is not of the dimension specified by {@code type}
	 */
	public <T> T getRealArray(DoubleArrayType<T> type) {
		return getAsJavaArray(type, _realValues);
	}

	/**
	 * Equivalent to {@code getRealArray(DoubleArrayType.DIM_2)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a two dimensional array
	 */
	public double[][] getRealArray2D() {
		return this.getRealArray(DoubleArrayType.DIM_2);
	}

	/**
	 * Equivalent to {@code getRealArray(DoubleArrayType.DIM_3)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a three dimensional array
	 */
	public double[][][] getRealArray3D() {
		return this.getRealArray(DoubleArrayType.DIM_3);
	}

	/**
	 * Equivalent to {@code getRealArray(DoubleArrayType.DIM_4)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a four dimensional array
	 */
	public double[][][][] getRealArray4D() {
		return this.getRealArray(DoubleArrayType.DIM_4);
	}

	/**
	 * Returns a {@code double} array of type {@code T} that holds the imaginary values from the MATLAB array.
	 * 
	 * @param <T>
	 * @param type
	 * @return 
	 * @throws ArrayDimensionException if the array is not of the dimension specified by {@code type}
	 * @throws IllegalStateException if the array is real
	 */
	public <T> T getImaginaryArray(DoubleArrayType<T> type) {
		if (_isReal) {
			throw new IllegalStateException("array is real");
		}

		return getAsJavaArray(type, _imaginaryValues);
	}

	/**
	 * Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_2)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a two dimensional array
	 * @throws IllegalStateException if the array is real
	 */
	public double[][] getImaginaryArray2D() {
		return this.getImaginaryArray(DoubleArrayType.DIM_2);
	}

	/**
	 * Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_3)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a three dimensional array
	 * @throws IllegalStateException if the array is real
	 */
	public double[][][] getImaginaryArray3D() {
		return this.getImaginaryArray(DoubleArrayType.DIM_3);
	}

	/**
	 * Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_4)}.
	 * 
	 * @return
	 * @throws ArrayDimensionException if the array is not a four dimensional array
	 * @throws IllegalStateException if the array is real
	 */
	public double[][][][] getImaginaryArray4D() {
		return this.getImaginaryArray(DoubleArrayType.DIM_4);
	}

	/**
	 * Returns {@code true} if the array has no imaginary values, {@code false} otherwise. Equivalent to the MATLAB
	 * {@code isreal} function.
	 * 
	 * @return 
	 */
	public boolean isReal() {
		return _isReal;
	}

	/**
	 * Returns the underlying linear array of real values. Returns the actual array, not a copy.
	 * 
	 * @return 
	 */
	double[] getRealLinearArray() {
		return _realValues;
	}

	/**
	 * Returns the underlying linear array of imaginary values. Returns the actual array, not a copy.
	 * 
	 * @return 
	 */
	double[] getImaginaryLinearArray() {
		return _imaginaryValues;
	}

	/**
	 * Returns a brief description of this array. The exact details of this representation are unspecified and are
	 * subject to change.
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "[" + this.getClass() +
				" dimensions=" + this.getDimensions() + "," +
				" linearLength=" + this.getLength() + "," +
				" lengths=" + Arrays.toString(_lengths) + "," +
				" fromMATLAB=" + _fromMatlab + "]";
	}

	/**
	 * Multidimensional indices to linear index. Similar to MATLAB's (@code sub2ind} function.
	 * 
	 * @param lengths the lengths of the array in each dimension
	 * @param indices
	 * @return
	 * @throws IllegalArgumentException thrown if the length of {@code lengths} and {@code indices} are not the same
	 */
	private static int multidimensionalIndicesToLinearIndex(int[] lengths, int[] indices) {
		if (lengths.length != indices.length) {
			throw new IllegalArgumentException("There must be an equal number of lengths [" + lengths.length + "] "
					+ "and indices [" + indices.length + "]");
		}

		int linearIndex = 0;

		int accumSize = 1;
		for (int i = 0; i < lengths.length; i++) {
			linearIndex += accumSize * indices[i];
			accumSize *= lengths[i];
		}

		return linearIndex;
	}

	/**
	 * Creates a {@code double} array of type {@code T} with the length of each dimension specified by {@code lengths}.
	 * As the array is created it is populated with the values of {@code linearArray}.
	 * 
	 * @param <T>
	 * @param linearArray
	 * @param outputArrayType
	 * @param lengths
	 * @return 
	 */
	private static <T> T multidimensionalize(double[] linearArray, Class<T> outputArrayType, int[] lengths) {
		return multidimensionalize_internal(linearArray, outputArrayType, lengths, 0, new int[0]);
	}

	/**
	 * The real logic of the {@link #multidimensionalize(double[], java.lang.Class, int[])} method. This method
	 * recurs on itself, hence the need for the extra parameters. This method does not store state in any external
	 * variables.
	 * 
	 * @param <T>
	 * @param linearArray
	 * @param outputArrayType
	 * @param lengths
	 * @param indexIntoLengths should be {@code 0} initially
	 * @param currIndices should be an empty integer array initially
	 * @return 
	 */
	@SuppressWarnings("unchecked")
	private static <T> T multidimensionalize_internal(double[] linearArray, Class<T> outputArrayType, int[] lengths,
			int indexIntoLengths, int[] currIndices) {
		Class<?> arrayType = outputArrayType.getComponentType();
		int arrayLength = lengths[indexIntoLengths];
		T array = (T) Array.newInstance(arrayType, arrayLength);

		//If what was created holds an array, then fill it
		if (arrayType.isArray()) {
			//If the array that was created holds the double array, double[]
			if (arrayType.equals(double[].class)) {
				//The index in the multidimensional array being created
				int[] primitiveArrayIndices = new int[currIndices.length + 2];
				System.arraycopy(currIndices, 0, primitiveArrayIndices, 0, currIndices.length);

				//Iterate over the created array, placing a double[] array in each index
				for (int i = 0; i < arrayLength; i++) {
					primitiveArrayIndices[primitiveArrayIndices.length - 2] = i;

					//Create the primitive array
					double[] primitiveArray = new double[lengths[lengths.length - 1]];

					//Fill the primitive array with values from the linear array
					for (int j = 0; j < primitiveArray.length; j++) {
						primitiveArrayIndices[primitiveArrayIndices.length - 1] = j;
						int linearIndex = multidimensionalIndicesToLinearIndex(lengths, primitiveArrayIndices);
						primitiveArray[j] = linearArray[linearIndex];
					}

					//Place primitive array into the enclosing array
					Array.set(array, i, primitiveArray);
				}
			} else {
				//Iterate over the created array, placing an array in each index (using recursion)
				for (int i = 0; i < arrayLength; i++) {
					int[] nextIndices = new int[currIndices.length + 1];
					System.arraycopy(currIndices, 0, nextIndices, 0, currIndices.length);
					nextIndices[nextIndices.length - 1] = i;

					Object innerArray = multidimensionalize_internal(linearArray, arrayType, lengths,
							indexIntoLengths + 1, nextIndices);
					Array.set(array, i, innerArray);
				}
			}
		}
		//If a double[] was just created, then the original request was to create a one dimensional array
		else {
			System.arraycopy(linearArray, 0, array, 0, arrayLength);
		}

		return array;
	}

	/**
	 * Determines the maximum length for each dimension of the array.
	 * 
	 * @param array
	 * @return 
	 */
	private static int[] computeBoundingLengths(Object array) {
		DoubleArrayType<?> type = DoubleArrayType.getInstanceUnsafe(array.getClass());
		int[] maxLengths = new int[type.getDimensions()];

		//The length of this array
		int arrayLength = Array.getLength(array);
		maxLengths[0] = arrayLength;

		//If the array holds arrays as its entries
		if (!array.getClass().getComponentType().equals(double.class)) {
			//For each entry in the array
			for (int i = 0; i < arrayLength; i++) {
				//childLengths' information will be one index ahead of maxLengths
				int[] childLengths = computeBoundingLengths(Array.get(array, i));
				for (int j = 0; j < childLengths.length; j++) {
					maxLengths[j + 1] = Math.max(maxLengths[j + 1], childLengths[j]);
				}
			}
		}

		return maxLengths;
	}

	/**
	 * Creates a linearized version of the {@code array} with maximum length in each dimension specified by
	 * {@code lengths}. No verification is performed that the dimensions of the array match the length of the lengths
	 * array.
	 * 
	 * @param array
	 * @param lengths
	 * @return 
	 */
	private static double[] linearize(Object array, int[] lengths) {
		//Create linear array with equal size of the array
		double[] linearArray = new double[getTotalSize(lengths)];

		//Fill linearArray with values from array
		linearize_internal(linearArray, array, lengths, new int[0]);

		return linearArray;
	}

	/**
	 * Performs the linearization using recursion.
	 * 
	 * @param linearArray array to be filled
	 * @param array source array
	 * @param lengths the lengths of the array for the initial array supplied before any recursion
	 * @param currIndices must initially be an empty integer array
	 */
	private static void linearize_internal(double[] linearArray, Object array, int[] lengths, int[] currIndices) {
		//Base case
		if (array.getClass().equals(double[].class)) {
			int[] doubleArrayIndices = new int[currIndices.length + 1];
			System.arraycopy(currIndices, 0, doubleArrayIndices, 0, currIndices.length);

			//Fill linear array with contents of the double[] array
			double[] doubleArray = (double[]) array;
			for (int i = 0; i < doubleArray.length; i++) {
				doubleArrayIndices[doubleArrayIndices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, doubleArrayIndices);
				linearArray[linearIndex] = doubleArray[i];
			}
		} else {
			int arrayLength = Array.getLength(array);
			for (int i = 0; i < arrayLength; i++) {
				int[] nextIndices = new int[currIndices.length + 1];
				System.arraycopy(currIndices, 0, nextIndices, 0, currIndices.length);
				nextIndices[nextIndices.length - 1] = i;

				linearize_internal(linearArray, Array.get(array, i), lengths, nextIndices);
			}
		}
	}

	/**
	 * Represents attempting to retrieve or manipulate a MATLAB array as the wrong dimension.
	 */
	public static class ArrayDimensionException extends RuntimeException {
		private static final long serialVersionUID = 0xC400L;

		private final int _actualNumberOfDimensions;
		private final int _usedAsNumberOfDimensions;

		ArrayDimensionException(int actualNumDim, int usedAsNumDim) {
			super("Array has " + actualNumDim + " dimension(s), it cannot be used as if it had " + usedAsNumDim +
					" dimension(s).");

			_actualNumberOfDimensions = actualNumDim;
			_usedAsNumberOfDimensions = usedAsNumDim;
		}

		/**
		 * The actual number of dimensions the array has.
		 * 
		 * @return 
		 */
		public int getActualNumberOfDimensions() {
			return _actualNumberOfDimensions;
		}

		/**
		 * The number of dimensions that were used when interacting with the array.
		 * 
		 * @return 
		 */
		public int getUsedNumberOfDimensions() {
			return _usedAsNumberOfDimensions;
		}
	}

	/**
	 * An array type of dimension 2 or greater which holds {@code double}s. Instances for dimensions 2 through 9 are
	 * available as {@code public static} fields.
	 * <br><br>
	 * This class is unconditionally thread-safe.
	 * 
	 * @param <T> an array of 2 or more dimensions which holds {@code double}s
	 */
	public static final class DoubleArrayType<T> {
		/**
		 * Caches loaded {@code DoubleArrayType}s.
		 */
		@SuppressWarnings("rawtypes")
		private static final Map<Class<?>, DoubleArrayType> CLASS_TO_ARRAY_TYPE = new ConcurrentHashMap<Class<?>, DoubleArrayType>();

		/**
		 * Representation of {@code double[][]} class.
		 */
		public static final DoubleArrayType<double[][]> DIM_2 = getInstance(double[][].class);

		/**
		 * Representation of {@code double[][][]} class.
		 */
		public static final DoubleArrayType<double[][][]> DIM_3 = getInstance(double[][][].class);

		/**
		 * Representation of {@code double[][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][]> DIM_4 = getInstance(double[][][][].class);

		/**
		 * Representation of {@code double[][][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][][]> DIM_5 = getInstance(double[][][][][].class);

		/**
		 * Representation of {@code double[][][][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][][][]> DIM_6 = getInstance(double[][][][][][].class);

		/**
		 * Representation of {@code double[][][][][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][][][][]> DIM_7 = getInstance(double[][][][][][][].class);

		/**
		 * Representation of {@code double[][][][][][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][][][][][]> DIM_8 = getInstance(double[][][][][][][][].class);

		/**
		 * Representation of {@code double[][][][][][][][][]} class.
		 */
		public static final DoubleArrayType<double[][][][][][][][][]> DIM_9 = getInstance(double[][][][][][][][][].class);

		/**
		 * The array class represented.
		 */
		private final Class<T> _arrayClass;

		/**
		 * The number of dimensions of the array type.
		 */
		private final int _numDimensions;

		/**
		 * Constructs a representation of a multidimensional array of {@code double}s.
		 * 
		 * @param arrayClass
		 * @throws IllegalArgumentException if the type is not an array holding {@code double}s
		 */
		private DoubleArrayType(Class<T> arrayClass) {
			if (!isDoubleArrayType(arrayClass)) {
				throw new IllegalArgumentException(arrayClass + " does not hold doubles");
			}

			_arrayClass = arrayClass;
			_numDimensions = getNumberOfDimensions(arrayClass);
		}

		/**
		 * Gets an instance of {@code DoubleArrayType<T>} where {@code T} is the type of {@code arrayType}. {@code T}
		 * must be an array of 1 or more dimensions that holds {@code double}s. This is intended for getting array types
		 * in excess of 9 dimensions, as dimensions 2 through 9 are represented by constants {@code DIM_2 ... DIM_9}.
		 * <br><br>
		 * Contrived example usage:<br>
		 * {@code DoubleArrayType<double[][][]> type3D = DoubleArrayType.getInstance(double[][][].class);}
		 * 
		 * @param <T>
		 * @param arrayType
		 * 
		 * @return
		 * 
		 * @throws IllegalArgumentException if the type is not an array holding {@code double}s or the type is of less
		 * than 2 dimensions
		 */
		public static <T> DoubleArrayType<T> getInstance(Class<T> arrayType) {
			if (arrayType.equals(double[].class)) {
				throw new IllegalArgumentException(arrayType + " not supported, must be 2 or more dimensions");
			}

			return getInstanceUnsafe(arrayType);
		}

		/**
		 * Behaves the same as {@link #getInstance(java.lang.Class)} except that {@code double[]} is valid. This is
		 * needed by some of the recursive algorithms in {@code MatlabNumericArray}.
		 */
		@SuppressWarnings("unchecked")
		static <T> DoubleArrayType<T> getInstanceUnsafe(Class<T> arrayType) {
			if (!CLASS_TO_ARRAY_TYPE.containsKey(arrayType)) {
				DoubleArrayType<T> type = new DoubleArrayType<T>(arrayType);
				CLASS_TO_ARRAY_TYPE.put(arrayType, type);
			}

			return CLASS_TO_ARRAY_TYPE.get(arrayType);
		}

		static DoubleArrayType<?> getInstance(int dimensions) {
			DoubleArrayType<?> type;

			//Construct the name of the class
			StringBuilder className = new StringBuilder(1 + dimensions);
			for (int i = 0; i < dimensions; i++) {
				className.append('[');
			}
			className.append('D');

			//Retrieve the class, and then getInstance the corresponding DoubleArrayType
			try {
				type = getInstanceUnsafe(Class.forName(className.toString()));
			} catch (ClassNotFoundException e) {
				type = null;
			}

			return type;
		}

		/**
		 * The number of dimensions of the array type.
		 * 
		 * @return 
		 */
		public int getDimensions() {
			return _numDimensions;
		}

		/**
		 * The type of array. The array holds {@code double}s, and may be of any dimension 2 or greater.
		 * 
		 * @return 
		 */
		public Class<T> getArrayClass() {
			return _arrayClass;
		}

		/**
		 * If {@code type} is an array of one or more dimensions which holds doubles.
		 * 
		 * @param type
		 * @return 
		 */
		private static boolean isDoubleArrayType(Class<?> type) {
			boolean isType;

			if (type.isArray()) {
				while (type.isArray()) {
					type = type.getComponentType();
				}

				isType = type.equals(double.class);
			} else {
				isType = false;
			}

			return isType;
		}

		/**
		 * Returns the number of dimensions the array type has. If {@code type} is not a type of array then {@code 0}
		 * will be returned.
		 * 
		 * @param type
		 * @return 
		 */
		private static int getNumberOfDimensions(Class<?> type) {
			int numDim = 0;
			while (type.isArray()) {
				numDim++;
				type = type.getComponentType();
			}

			return numDim;
		}

		/**
		 * Returns a brief description of this double array type. The exact details of this representation are
		 * unspecified and are subject to change.
		 * 
		 * @return 
		 */
		@Override
		public String toString() {
			return "[" + this.getClass().getName() + " class=" + _arrayClass + ", dimensions=" + _numDimensions + "]";
		}
	}
}


<|start_filename|>src/matlabcontrol/Configuration.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.logging.Logger;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * Contains important configuration information regarding the setup of MATLAB and matlabcontrol.
 * 
 * @since 3.1.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class Configuration {

	private static Logger sLog = Logger.getLogger(Configuration.class.getName());

	private Configuration() {}

	/**
	 * If running on OS X.
	 * 
	 * @return
	 */
	static boolean isOSX() {
		return getOperatingSystem().startsWith("Mac OS X");
	}

	/**
	 * If running on Windows.
	 * 
	 * @return
	 */
	static boolean isWindows() {
		return getOperatingSystem().startsWith("Windows");
	}

	/**
	 * If running on Linux.
	 * 
	 * @return
	 */
	static boolean isLinux() {
		return getOperatingSystem().startsWith("Linux");
	}

	/**
	 * Gets a string naming the operating system.
	 * 
	 * @return
	 */
	static String getOperatingSystem() {
		return System.getProperty("os.name");
	}

	/**
	 * Returns the location or alias of MATLAB on an operating system specific basis.
	 * <br><br>
	 * For OS X this will be the location, for Windows or Linux this will be an alias. For any other operating system an
	 * exception will be thrown.
	 * 
	 * @return
	 * @throws MatlabConnectionException thrown if the location of MATLAB cannot be determined on OS X, or the alias
	 *                                       cannot be determined because the operating system is not Windows or Linux
	 */
	static String getMatlabLocation() throws MatlabConnectionException {
		//Determine the location of MATLAB
		String matlabLoc;

		//OS X
		if (isOSX()) {
			matlabLoc = getOSXMatlabLocation();
		}
		//Windows or Linux
		else if (isWindows() || isLinux()) {
			matlabLoc = "matlab";
		}
		//Other unsupported operating system
		else {
			throw new MatlabConnectionException("MATLAB's location or alias can only be determined for OS X, " +
					"Windows, & Linux. For this operating system the location or alias must be specified " +
					"explicitly.");
		}

		return matlabLoc;
	}

	/**
	 * Determines the location of the MATLAB executable on OS X. If multiple versions are found, the last one
	 * encountered will be used.
	 * 
	 * @return MATLAB's location on OS X
	 * 
	 * @throws MatlabConnectionException if the location cannot be determined
	 */
	@SuppressFBWarnings(value = "DMI_HARDCODED_ABSOLUTE_FILENAME", justification = "OS X is very predictable")
	private static String getOSXMatlabLocation() throws MatlabConnectionException {
		//Search for MATLAB in the Applications directory
		String matlabName = null;
		String[] files = new File("/Applications/").list();
		if (files != null) {
			for (String fileName : files) {
				if (fileName.startsWith("MATLAB")) {
					matlabName = fileName;
				}
			}
		}

		//If no installation is found
		if (matlabName == null) {
			throw new MatlabConnectionException("No installation of MATLAB on OS X can be found");
		}

		//Build path to the executable location
		String matlabLocation = "/Applications/" + matlabName + "/bin/matlab";

		//Check the path actually exists
		if (!new File(matlabLocation).exists()) {
			throw new MatlabConnectionException("An installation of MATLAB on OS X was found but the main " +
					"executable file was not found in the anticipated location: " + matlabLocation);
		}

		return matlabLocation;
	}

	/**
	 * Converts the classpath into RMI's codebase format. The codebase format is a list of URL formatted strings
	 * separated by spaces. As the application may be running in a different directory, paths are made absolute.
	 * 
	 * @return codebase
	 * @throws MatlabConnectionException
	 */
	static String getClassPathAsRMICodebase() throws MatlabConnectionException {
		String entry = "";
		try {
			StringBuilder codebaseBuilder = new StringBuilder();
			String[] paths = System.getProperty("java.class.path", "").split(File.pathSeparator);

			for (int i = 0; i < paths.length; i++) {
				File f = new File(paths[i]);
				if (f.exists() && !f.isDirectory()) {
					entry = new File(paths[i]).getCanonicalFile().toURI().toURL().getPath();
					codebaseBuilder.append("file://");
					codebaseBuilder.append(entry);
				}
				if (i != paths.length - 1) {
					codebaseBuilder.append(" ");
				}
			}

			return codebaseBuilder.toString();
		} catch (IOException e) {
			sLog.severe("Unable to resolve classpath entry: " + entry);
			throw new MatlabConnectionException("Unable to resolve classpath entry", e);
		}
	}

	/**
	 * Converts the classpath into individual canonical entries.
	 * 
	 * @return
	 * @throws MatlabConnectionException
	 */
	static String[] getClassPathAsCanonicalPaths() throws MatlabConnectionException {
		try {
			String[] paths = System.getProperty("java.class.path", "").split(File.pathSeparator);

			for (int i = 0; i < paths.length; i++) {
				File f = new File(paths[i]);
				if (f.exists()) {
					paths[i] = f.getCanonicalPath();
				} else {
					sLog.severe("Classpath entry " + paths[i] + " not found. Adding absolute path instead.");
					paths[i] = new File(paths[i]).getAbsolutePath();
				}
			}

			return paths;
		} catch (IOException e) {
			throw new MatlabConnectionException("Unable to resolve classpath entry", e);
		}
	}

	/**
	 * Determines the location of this code at runtime. Either it will be the directory or jar this .class file is in.
	 * (That is, the .class file built from compiling this .java file.) Returned as a string so that it may be used by
	 * MATLAB.
	 * <br><br>
	 * It may not be possible to determine the location of the code due to the class loader for this class. The class
	 * loader will determine if a code source was set and the format of its location. Due to the problematic nature
	 * of determining code location this method has been designed to throw exceptions with very detailed exceptions to
	 * aid in improving this method further based on anticipated bug reports.
	 * 
	 * @return
	 * @throws MatlabConnectionException
	 */
	static String getSupportCodeLocation() throws MatlabConnectionException {
		//domain should never be null
		ProtectionDomain domain = Configuration.class.getProtectionDomain();

		//codeSource can be null
		CodeSource codeSource = domain.getCodeSource();
		if (codeSource != null) {
			//url can be null
			URL url = codeSource.getLocation();
			if (url != null) {
				//Convert from url to absolute path
				try {
					// generate canonical file using URL path
					File file = new File(url.getPath()).getCanonicalFile();
					if (file.exists()) {
						return file.getAbsolutePath();
					} else {
						// generate canonical file using URI
						file = new File(url.toURI()).getCanonicalFile();
						if (file.exists()) {
							return file.getAbsolutePath();
						} else {
							ClassLoader loader = Configuration.class.getClassLoader();
							throw new MatlabConnectionException("Support code location was determined improperly." +
									" Location does not exist.\n" +
									"Location determined as: " + file.getAbsolutePath() + "\n" +
									"File: " + file + "\n" +
									"URL Location: " + url + "\n" +
									"Code Source: " + codeSource + "\n" +
									"Protection Domain: " + domain + "\n" +
									"Class Loader: " + loader +
									(loader == null ? "" : "\nClass Loader Class: " + loader.getClass()));
						}
					}
				}
				//Unable to resolve canconical path
				catch (IOException e) {
					ClassLoader loader = Configuration.class.getClassLoader();
					throw new MatlabConnectionException("Support code location could not be determined. " +
							"Could not resolve canonical path.\n" +
							"URL Location: " + url + "\n" +
							"Code Source: " + codeSource + "\n" +
							"Protection Domain: " + domain + "\n" +
							"Class Loader: " + loader +
							(loader == null ? "" : "\nClass Loader Class: " + loader.getClass()), e);
				} catch (URISyntaxException e) {
					ClassLoader loader = Configuration.class.getClassLoader();
					throw new MatlabConnectionException("Support code location could not be determined. " +
							"Could not convert URI location to file path.\n" +
							"URL Location: " + url + "\n" +
							"Code Source: " + codeSource + "\n" +
							"Protection Domain: " + domain + "\n" +
							"Class Loader: " + loader +
							(loader == null ? "" : "\nClass Loader Class: " + loader.getClass()), e);
				}
			}
			//url was null
			else {
				ClassLoader loader = Configuration.class.getClassLoader();
				throw new MatlabConnectionException("Support code location could not be determined. " +
						"Could not get URL from CodeSource.\n" +
						"Code Source: " + codeSource + "\n" +
						"Protection Domain: " + domain + "\n" +
						"Class Loader: " + loader +
						(loader == null ? "" : "\nClass Loader Class: " + loader.getClass()));
			}
		}
		//code source was null
		else {
			ClassLoader loader = Configuration.class.getClassLoader();
			throw new MatlabConnectionException("Support code location could not be determined. " +
					"Could not get CodeSource from ProtectionDomain.\n" +
					"Protection Domain: " + domain + "\n" +
					"Class Loader: " + loader +
					(loader == null ? "" : "\nClass Loader Class: " + loader.getClass()));
		}
	}

	/**
	 * Whether this code is running inside of MATLAB.
	 * 
	 * @return
	 */
	static boolean isRunningInsideMatlab() {
		boolean available;
		try {
			//Load the class com.mathworks.jmi.Matlab and then calls its static method isMatlabAvailable()
			//All of this is done with reflection so that this class does not cause the class loader to attempt
			//to load JMI classes (and if not running inside of MATLAB - fail)
			Class<?> matlabClass = Class.forName("com.mathworks.jmi.Matlab");
			Method isAvailableMethod = matlabClass.getMethod("isMatlabAvailable");
			available = (Boolean) isAvailableMethod.invoke(null);
		} catch (Throwable t) {
			available = false;
		}

		return available;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabDoubleArray.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.Arrays;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @param <T> {@code double} array type, ex. {@code double[]}, {@code double[][]}, {@code double[][][]}, ...
 */
public class MatlabDoubleArray<T> extends MatlabNumberArray<double[], T> {
	MatlabDoubleArray(double[] real, double[] imag, int[] lengths) {
		super(double[].class, real, imag, lengths);
	}

	public static <T> MatlabDoubleArray<T> getInstance(T real, T imaginary) {
		return new MatlabDoubleArray<T>(real, imaginary);
	}

	private MatlabDoubleArray(T real, T imaginary) {
		super(double[].class, real, imaginary);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabDouble getElementAtLinearIndex(int index) {
		return new MatlabDouble(_real[index], (_imag == null ? 0 : _imag[index]));
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws IllegalArgumentException {@inheritDoc}
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabDouble getElementAtIndices(int row, int column, int... pages) {
		int linearIndex = getLinearIndex(row, column, pages);

		return new MatlabDouble(_real[linearIndex], (_imag == null ? 0 : _imag[linearIndex]));
	}

	@Override
	boolean equalsRealArray(double[] other) {
		return Arrays.equals(_real, other);
	}

	@Override
	boolean equalsImaginaryArray(double[] other) {
		return Arrays.equals(_imag, other);
	}

	@Override
	int hashReal() {
		return Arrays.hashCode(_real);
	}

	@Override
	int hashImaginary() {
		return Arrays.hashCode(_imag);
	}

	@Override
	boolean containsNonZero(double[] array) {
		boolean contained = false;

		for (double val : array) {
			if (val != 0.0d) {
				contained = true;
				break;
			}
		}

		return contained;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabDoubleSparseMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabDoubleSparseMatrix extends MatlabDoubleMatrix<double[][]> {
	private final SparseArray<double[]> _array;

	MatlabDoubleSparseMatrix(int[] linearIndices, int[] rowIndices, int[] colIndices, double[] real, double[] imag,
			int numRows, int numCols) {
		_array = new SparseArray<double[]>(double[].class, linearIndices, rowIndices, colIndices, real, imag,
				numRows, numCols);
	}

	MatlabDoubleSparseMatrix(int[] rowIndices, int[] colIndices, double[] real, double[] imag, int numRows, int numCols) {
		_array = new SparseArray<double[]>(double[].class, rowIndices, colIndices, real, imag, numRows, numCols);
	}

	@Override
	BaseArray<double[], double[][]> getBaseArray() {
		return _array;
	}

	private double getRealElementAtSparseIndex(int sparseIndex) {
		double val = 0;
		if (sparseIndex >= 0) {
			val = _array._realValues[sparseIndex];
		}

		return val;
	}

	private double getImaginaryElementAtSparseIndex(int sparseIndex) {
		double val = 0;
		if (!_array.isReal() && sparseIndex >= 0) {
			val = _array._imagValues[sparseIndex];
		}

		return val;
	}

	@Override
	public double getRealElementAtLinearIndex(int linearIndex) {
		return this.getRealElementAtSparseIndex(_array.getSparseIndexForLinearIndex(linearIndex));
	}

	@Override
	public double getImaginaryElementAtLinearIndex(int linearIndex) {
		return this.getImaginaryElementAtSparseIndex(_array.getSparseIndexForLinearIndex(linearIndex));
	}

	@Override
	public double getRealElementAtIndices(int row, int column) {
		return this.getRealElementAtSparseIndex(_array.getSparseIndexForIndices(row, column));
	}

	@Override
	public double getRealElementAtIndices(int row, int column, int page) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using 3 indices");
	}

	@Override
	public double getRealElementAtIndices(int row, int column, int[] pages) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using " +
				(2 + pages.length) + " indices");
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column) {
		return this.getImaginaryElementAtSparseIndex(_array.getSparseIndexForIndices(row, column));
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column, int page) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using 3 indices");
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column, int[] pages) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using " +
				(2 + pages.length) + " indices");
	}

	@Override
	public MatlabDouble getElementAtLinearIndex(int linearIndex) {
		int sparseIndex = _array.getSparseIndexForLinearIndex(linearIndex);

		return new MatlabDouble(this.getRealElementAtSparseIndex(sparseIndex),
				this.getImaginaryElementAtSparseIndex(sparseIndex));
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column) {
		int sparseIndex = _array.getSparseIndexForIndices(row, column);

		return new MatlabDouble(this.getRealElementAtSparseIndex(sparseIndex),
				this.getImaginaryElementAtSparseIndex(sparseIndex));
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column, int page) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using 3 indices");
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column, int... pages) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using " +
				(2 + pages.length) + " indices");
	}

	@Override
	public int hashCode() {
		return _array.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		boolean equal = false;
		if (this == obj) {
			equal = true;
		} else if (obj != null && this.getClass().equals(obj.getClass())) {
			MatlabDoubleSparseMatrix other = (MatlabDoubleSparseMatrix) obj;
			equal = _array.equals(other._array);
		}

		return equal;
	}
}


<|start_filename|>src/matlabcontrol/link/ArrayMultidimensionalizer.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import static matlabcontrol.link.ArrayUtils.*;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.link.MatlabType.MatlabTypeGetter;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@SuppressWarnings("rawtypes")
class ArrayMultidimensionalizer {
	static class PrimitiveArrayGetter implements MatlabTypeGetter<Object> {
		private static final long serialVersionUID = -3228683201238234004L;
		private int[] _lengths;
		private Object _array;

		private boolean _retreived = false;

		private final boolean _getRealPart;
		private final boolean _keepLinear;

		public PrimitiveArrayGetter(boolean realPart, boolean keepLinear) {
			_getRealPart = realPart;
			_keepLinear = keepLinear;
		}

		public boolean isRealPart() {
			return _getRealPart;
		}

		public int[] getLengths() {
			return _lengths;
		}

		/**
		 * May be null if this represents the imaginary part and the array has no imaginary values or the array was
		 * empty.
		 * 
		 * @return 
		 */
		@Override
		public Object retrieve() {
			//Validate
			if (!_retreived) {
				throw new IllegalStateException("array has not yet been retrieved");
			}

			if (_array != null && !_keepLinear) {
				return multidimensionalize(_array, _lengths);
			} else {
				return _array;
			}
		}

		@Override
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			//Retrieve lengths of array
			double[] size = (double[]) ops.returningEval("size(" + variableName + ");", 1)[0];
			_lengths = new int[size.length];
			for (int i = 0; i < size.length; i++) {
				_lengths[i] = (int) size[i];
			}

			//Retrieve array
			String name = (String) ops.returningEval("genvarname('" + variableName + "_getter', who);", 1)[0];
			ops.setVariable(name, this);
			try {
				if (_getRealPart) {
					ops.eval(name + ".setArray(reshape(" + variableName + ", 1, []));");
				} else {
					//If the array has an imaginary part, retrieve it
					boolean isReal = ((boolean[]) ops.returningEval("isreal(" + variableName + ");", 1)[0])[0];
					if (!isReal) {
						ops.eval(name + ".setArray(imag(reshape(" + variableName + ", 1, [])));");
					}
				}
			} finally {
				ops.eval("clear " + name);
			}

			_retreived = true;
		}

		//The following methods are to be called only from MATLAB to pass in the array

		public void setArray(byte[] array) {
			_array = array;
		}

		public void setArray(short[] array) {
			_array = array;
		}

		public void setArray(int[] array) {
			_array = array;
		}

		public void setArray(long[] array) {
			_array = array;
		}

		public void setArray(float[] array) {
			_array = array;
		}

		public void setArray(double[] array) {
			_array = array;
		}

		public void setArray(char[] array) {
			_array = array;
		}

		public void setArray(boolean[] array) {
			_array = array;
		}
	}

	/**
	 * Creates a rectangular multidimensional array from {@code linearArray} with the length of each dimension specified
	 * by {@code lengths}. The length of the array must equal the total size specified by {@code lengths}.
	 * 
	 * @param <T>
	 * @param linearArray a primitive linear array
	 * @param lengths length of each dimension
	 * @return multidimensional array
	 */
	static Object multidimensionalize(Object linearArray, int[] lengths) {
		//Validate primitive single dimension array
		if (linearArray == null || !linearArray.getClass().isArray() &&
				!linearArray.getClass().getComponentType().isPrimitive()) {
			throw new RuntimeException("linear array must be a single dimension primitive array");
		}

		//Validate lengths
		if (getNumberOfElements(lengths) != Array.getLength(linearArray)) {
			throw new RuntimeException("linear array's length does not match the total size of the provided " +
					"multidimensional lengths\n" +
					"Linear Array Length: " + Array.getLength(linearArray) + "\n" +
					"Multidimensional Lengths: " + Arrays.toString(lengths) + "\n" +
					"Multidimensional Total Size: " + getNumberOfElements(lengths));
		}

		Class componentType = linearArray.getClass().getComponentType();
		Class outputArrayType = getArrayClass(componentType, lengths.length);
		ArrayFillOperation fillOperation = FILL_OPERATIONS.get(componentType);

		return multidimensionalize_internal(linearArray, outputArrayType, fillOperation, lengths, 0, new int[lengths.length]);
	}

	/**
	 * The real logic of the multidimensionalize. This method recurs on itself, hence the need for the extra parameters.
	 * This method does not store state in any external variables.
	 * 
	 * @param linearArray
	 * @param outputArrayType
	 * @param fillOperation operation used to fill in single dimension pieces of the array
	 * @param lengths
	 * @param depth should be {@code 0} initially
	 * @param indices must be the length of {@code lengths}
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static Object multidimensionalize_internal(Object linearArray, Class<?> outputArrayType,
			ArrayFillOperation fillOperation, int[] lengths, int depth, int[] indices) {
		Class<?> componentType = outputArrayType.getComponentType();
		int arrayLength = lengths[depth];
		Object array = Array.newInstance(componentType, arrayLength);

		//If what was created holds an array, then fill it
		if (componentType.isArray()) {
			//If the array that was created holds the primitive array: double[], int[], boolean[] etc.
			if (componentType.getComponentType().isPrimitive()) {
				//Iterate over the created array, placing a primitive array in each index
				for (int i = 0; i < arrayLength; i++) {
					indices[indices.length - 2] = i;

					//Create the primitive array
					Object primitiveArray = Array.newInstance(componentType.getComponentType(), lengths[lengths.length - 1]);

					//Fill the primitive array with values from the linear array
					fillOperation.fill(primitiveArray, linearArray, indices, lengths);

					//Place primitive array into the enclosing array
					Array.set(array, i, primitiveArray);
				}
			} else {
				//Iterate over the created array, placing an array in each index (using recursion)
				for (int i = 0; i < arrayLength; i++) {
					indices[depth] = i;

					Object innerArray = multidimensionalize_internal(linearArray, componentType,
							fillOperation, lengths, depth + 1, indices);
					Array.set(array, i, innerArray);
				}
			}
		}
		//If the componentType is not an array, then the original request was to create a one dimensional array
		else {
			System.arraycopy(linearArray, 0, array, 0, arrayLength);
		}

		return array;
	}

	private static final Map<Class<?>, ArrayFillOperation<?>> FILL_OPERATIONS;

	static {
		Map<Class<?>, ArrayFillOperation<?>> map = new HashMap<Class<?>, ArrayFillOperation<?>>();

		map.put(byte.class, new ByteArrayFillOperation());
		map.put(short.class, new ShortArrayFillOperation());
		map.put(int.class, new IntArrayFillOperation());
		map.put(long.class, new LongArrayFillOperation());
		map.put(float.class, new FloatArrayFillOperation());
		map.put(double.class, new DoubleArrayFillOperation());
		map.put(boolean.class, new BooleanArrayFillOperation());
		map.put(char.class, new CharArrayFillOperation());

		FILL_OPERATIONS = Collections.unmodifiableMap(map);
	}

	private static interface ArrayFillOperation<T> {
		public void fill(T dst, T src, int[] indices, int[] lengths);
	}

	private static class ByteArrayFillOperation implements ArrayFillOperation<byte[]> {
		@Override
		public void fill(byte[] dst, byte[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class ShortArrayFillOperation implements ArrayFillOperation<short[]> {
		@Override
		public void fill(short[] dst, short[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class IntArrayFillOperation implements ArrayFillOperation<int[]> {
		@Override
		public void fill(int[] dst, int[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class LongArrayFillOperation implements ArrayFillOperation<long[]> {
		@Override
		public void fill(long[] dst, long[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class FloatArrayFillOperation implements ArrayFillOperation<float[]> {
		@Override
		public void fill(float[] dst, float[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class DoubleArrayFillOperation implements ArrayFillOperation<double[]> {
		@Override
		public void fill(double[] dst, double[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class BooleanArrayFillOperation implements ArrayFillOperation<boolean[]> {
		@Override
		public void fill(boolean[] dst, boolean[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}

	private static class CharArrayFillOperation implements ArrayFillOperation<char[]> {
		@Override
		public void fill(char[] dst, char[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < dst.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[i] = src[linearIndex];
			}
		}
	}
}


<|start_filename|>src/matlabcontrol/internal/MatlabRMIClassLoaderSpi.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.internal;

import java.io.File;
import java.net.MalformedURLException;
import java.rmi.server.RMIClassLoader;
import java.rmi.server.RMIClassLoaderSpi;

/**
 * <strong>Internal Use Only</strong>
 * <br><br>
 * This class must be public so that it can be created via reflection by {@link RemoteClassLoader}. If it were package
 * private it would result in an {@link IllegalAccessError} because only classes in the same package as a package
 * private class may construct it (even via reflection). It has been placed in the {@code matlabcontrol.internal}
 * package to make it clear it is not intended for use by users of matlabcontrol.
 * <br><br>
 * A custom service provider for the RMI class loader. Allows for loading classes sent from the external JVM and
 * providing annotations so that the external JVM may load classes defined only in the MATLAB JVM. Loading classes from
 * the external JVM could be accomplished by setting {@code java.rmi.server.codebase} property in the external JVM but
 * that could interfere with other uses of RMI in the application. There is no way to always sending the correct
 * annotations without this custom rmi class loader spi. While the {@code java.rmi.server.codebase} property could be
 * set in the MATLAB JVM, the property is checked only at load time. This would mean that class definitions added
 * dynamically with {@code javaaddpath} could not be sent.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * 
 */
public class MatlabRMIClassLoaderSpi extends RMIClassLoaderSpi {
	/**
	 * Loading of classes is delegated to the default {@link RMIClassLoaderSpi}.
	 */
	private final RMIClassLoaderSpi _delegateLoaderSpi = RMIClassLoader.getDefaultProviderInstance();

	/**
	 * The codebase of the external virtual machine which has a proxy that can interact with this session of MATLAB.
	 * This is done instead of setting the {@code java.rmi.server.codebase} property so that matlabcontrol does not
	 * interfere with any other uses of RMI in the application.
	 */
	private static volatile String _remoteCodebase = null;

	/**
	 * Sets the codebase of the currently connected external JVM. This should be called only once per connection to an
	 * external JVM and should occur before users of the API can send objects over RMI.
	 * 
	 * @param remoteCodebase 
	 */
	public static void setCodebase(String remoteCodebase) {
		_remoteCodebase = remoteCodebase;
	}

	@Override
	public Class<?> loadClass(String codebase, String name, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException {
		return _delegateLoaderSpi.loadClass(_remoteCodebase, name, defaultLoader);
	}

	@Override
	public Class<?> loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException {
		return _delegateLoaderSpi.loadProxyClass(_remoteCodebase, interfaces, defaultLoader);
	}

	@Override
	public ClassLoader getClassLoader(String codebase) throws MalformedURLException {
		return _delegateLoaderSpi.getClassLoader(_remoteCodebase);
	}

	/**
	 * {@inheritDoc}
	 * <br><br>
	 * The returned annotation becomes the {@code codebase} argument in
	 * {@link #loadClass(java.lang.String, java.lang.String, java.lang.ClassLoader)} when the {@code RMIClassLoaderSpi}
	 * in the receiving JVM attempts to load {@code clazz}. This allows for classes defined in MATLAB but not in the
	 * receiving JVM to find and load the class definition.
	 * 
	 * @param clazz
	 * @return 
	 */
	@Override
	public String getClassAnnotation(Class<?> clazz) {
		if (clazz == null) {
			throw new NullPointerException("class may not be null");
		}

		String annotation = null;

		//If the class has a code source, meaning it is not part of the Java Runtime Environment
		if (clazz.getProtectionDomain().getCodeSource() != null) {
			//This convoluted way of determining the code source location is necessary due to a bug in early versions of
			//Java 6 on Windows (such as what is used by MATLAB R2007b) which puts a space in the code source's URL.
			//A space in the URL will cause the receiver of this annotation to treat it as a path separator, which would
			//be very problematic and likely cause invalid protocol exceptions.
			try {
				File file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().getPath());
				annotation = file.toURI().toURL().toString();
			} catch (MalformedURLException e) {}
		}

		return annotation;
	}
}


<|start_filename|>src/matlabcontrol/JMIWrapperRemoteImpl.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.RemoteException;

/**
 * Passes method calls off to {@link JMIWrapper}.
 * <br><br>
 * Methods called on this proxy will be performed inside of the JVM that created this object. This class is only created
 * inside of the MATLAB's JVM and so {@code JMIWrapper}'s calls will be able to communicate with MATLAB.
 * <br><br>
 * These methods are documented in {@link MatlabProxy}.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class JMIWrapperRemoteImpl extends LocalHostRMIHelper.LocalHostRemoteObject implements JMIWrapperRemote {
	private static final long serialVersionUID = 6263244863419922018L;

	public JMIWrapperRemoteImpl() throws RemoteException {}

	@Override
	public void exit() {
		JMIWrapper.exit();
	}

	@Override
	public void eval(String command) throws MatlabInvocationException {
		JMIWrapper.eval(command);
	}

	@Override
	public Object[] returningEval(String command, int nargout) throws MatlabInvocationException {
		return JMIWrapper.returningEval(command, nargout);
	}

	@Override
	public void feval(String command, Object... args) throws MatlabInvocationException {
		JMIWrapper.feval(command, args);
	}

	@Override
	public Object[] returningFeval(String command, int nargout, Object... args) throws MatlabInvocationException {
		return JMIWrapper.returningFeval(command, nargout, args);
	}

	@Override
	public void setVariable(String variableName, Object value) throws MatlabInvocationException {
		JMIWrapper.setVariable(variableName, value);
	}

	@Override
	public Object getVariable(String variableName) throws MatlabInvocationException {
		return JMIWrapper.getVariable(variableName);
	}

	@Override
	public <T> T invokeAndWait(MatlabProxy.MatlabThreadCallable<T> callable) throws MatlabInvocationException {
		return JMIWrapper.invokeAndWait(callable);
	}

	@Override
	public void checkConnection() {}
}


<|start_filename|>src/matlabcontrol/RemoteMatlabProxy.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.MarshalException;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Allows for calling MATLAB from <strong>outside</strong> of MATLAB.
 * 
 * @since 3.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class RemoteMatlabProxy extends MatlabProxy {
	/**
	 * The remote JMI wrapper which is a remote object connected over RMI.
	 */
	private final JMIWrapperRemote _jmiWrapper;

	/**
	 * The receiver for the proxy. While the receiver is bound to the RMI registry and a reference is maintained
	 * (the RMI registry uses weak references), the connection to MATLAB's JVM will remain active. The JMI wrapper,
	 * while a remote object, is not bound to the registry, and will not keep the RMI thread running.
	 */
	private final RequestReceiver _receiver;

	/**
	 * A timer that periodically checks if still connected.
	 */
	private final Timer _connectionTimer;

	/**
	 * Whether the proxy is connected. If the value is {@code false} the proxy is definitely disconnected. If the value
	 * is {@code true} then the proxy <i>may</i> be disconnected. The accuracy of this will be checked then the next
	 * time {@link #isConnected()} is called and this value will be updated if necessary.
	 */
	private volatile boolean _isConnected = true;

	/**
	 * The duration (in milliseconds) between checks to determine if still connected.
	 */
	private static final int CONNECTION_CHECK_PERIOD = 1000;

	/**
	 * The proxy is never to be created outside of this package, it is to be constructed after a
	 * {@link JMIWrapperRemote} has been received via RMI.
	 * 
	 * @param internalProxy
	 * @param receiver
	 * @param id
	 * @param existingSession
	 */
	RemoteMatlabProxy(JMIWrapperRemote internalProxy, RequestReceiver receiver, Identifier id, boolean existingSession) {
		super(id, existingSession);

		_connectionTimer = new Timer("MLC Connection Listener " + id);
		_jmiWrapper = internalProxy;
		_receiver = receiver;
	}

	/**
	 * Initializes aspects of the proxy that cannot be done safely in the constructor without leaking a reference to
	 * {@code this}.
	 */
	void init() {
		_connectionTimer.schedule(new CheckConnectionTask(), CONNECTION_CHECK_PERIOD, CONNECTION_CHECK_PERIOD);
	}

	private class CheckConnectionTask extends TimerTask {
		@Override
		public void run() {
			if (!RemoteMatlabProxy.this.isConnected()) {
				//If not connected, perform disconnection so RMI thread can terminate
				RemoteMatlabProxy.this.disconnect();

				//Notify listeners
				notifyDisconnectionListeners();

				//Cancel timer, which will terminate the timer's thread
				_connectionTimer.cancel();
			}
		}
	}

	@Override
	public boolean isRunningInsideMatlab() {
		return false;
	}

	@Override
	public boolean isConnected() {
		//If believed to be connected, verify this is up to date information
		if (_isConnected) {
			boolean connected;
			//Call a remote method, if it throws a RemoteException then it is no longer connected
			try {
				_jmiWrapper.checkConnection();
				connected = true;
			} catch (RemoteException e) {
				connected = false;
			}

			_isConnected = connected;
		}

		return _isConnected;
	}

	@Override
	public boolean disconnect() {
		_connectionTimer.cancel();

		//Unexport the receiver so that the RMI threads can shut down
		try {
			//If succesfully exported, then definitely not connected
			//If the export failed, we still might be connected, isConnected() will check
			_isConnected = !UnicastRemoteObject.unexportObject(_receiver, true);
		}
		//If it is not exported, that's ok because we were trying to unexport it
		catch (NoSuchObjectException e) {}

		return this.isConnected();
	}

	// Methods which interact with MATLAB (and helper methods and interfaces)

	private static interface RemoteInvocation<T> {
		public T invoke() throws RemoteException, MatlabInvocationException;
	}

	private <T> T invoke(RemoteInvocation<T> invocation) throws MatlabInvocationException {
		if (!_isConnected) {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		} else {
			try {
				return invocation.invoke();
			} catch (UnmarshalException e) {
				throw MatlabInvocationException.Reason.UNMARSHAL.asException(e);
			} catch (MarshalException e) {
				throw MatlabInvocationException.Reason.MARSHAL.asException(e);
			} catch (RemoteException e) {
				if (this.isConnected()) {
					throw MatlabInvocationException.Reason.UNKNOWN.asException(e);
				} else {
					throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException(e);
				}
			}
		}
	}

	@Override
	public void setVariable(final String variableName, final Object value) throws MatlabInvocationException {
		this.invoke(new RemoteInvocation<Void>() {
			@Override
			public Void invoke() throws RemoteException, MatlabInvocationException {
				_jmiWrapper.setVariable(variableName, value);

				return null;
			}
		});
	}

	@Override
	public Object getVariable(final String variableName) throws MatlabInvocationException {
		return this.invoke(new RemoteInvocation<Object>() {
			@Override
			public Object invoke() throws RemoteException, MatlabInvocationException {
				return _jmiWrapper.getVariable(variableName);
			}
		});
	}

	@Override
	public void exit() throws MatlabInvocationException {
		this.invoke(new RemoteInvocation<Void>() {
			@Override
			public Void invoke() throws RemoteException, MatlabInvocationException {
				_jmiWrapper.exit();

				return null;
			}
		});
	}

	@Override
	public void eval(final String command) throws MatlabInvocationException {
		this.invoke(new RemoteInvocation<Void>() {
			@Override
			public Void invoke() throws RemoteException, MatlabInvocationException {
				_jmiWrapper.eval(command);

				return null;
			}
		});
	}

	@Override
	public Object[] returningEval(final String command, final int nargout) throws MatlabInvocationException {
		return this.invoke(new RemoteInvocation<Object[]>() {
			@Override
			public Object[] invoke() throws RemoteException, MatlabInvocationException {
				return _jmiWrapper.returningEval(command, nargout);
			}
		});
	}

	@Override
	public void feval(final String functionName, final Object... args) throws MatlabInvocationException {
		this.invoke(new RemoteInvocation<Void>() {
			@Override
			public Void invoke() throws RemoteException, MatlabInvocationException {
				_jmiWrapper.feval(functionName, args);

				return null;
			}
		});
	}

	@Override
	public Object[] returningFeval(final String functionName, final int nargout, final Object... args)
			throws MatlabInvocationException {
		return this.invoke(new RemoteInvocation<Object[]>() {
			@Override
			public Object[] invoke() throws RemoteException, MatlabInvocationException {
				return _jmiWrapper.returningFeval(functionName, nargout, args);
			}
		});
	}

	@Override
	public <T> T invokeAndWait(final MatlabThreadCallable<T> callable) throws MatlabInvocationException {
		return this.invoke(new RemoteInvocation<T>() {
			@Override
			public T invoke() throws RemoteException, MatlabInvocationException {
				return _jmiWrapper.invokeAndWait(callable);
			}
		});
	}
}


<|start_filename|>src/matlabcontrol/MatlabSession.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * An implementation of this interface is bound to a RMI registry, representing this session of MATLAB.
 *
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
interface MatlabSession extends Remote {
	/**
	 * Attempts a connection to this session of MATLAB. If this session is available for connection it will send a
	 * {@link JMIWrapperRemote} to the receiver and {@code true} will be returned. Otherwise {@code false} will be
	 * returned and no other action will be taken.
	 * 
	 * @param receiverID
	 * @param port
	 * @throws RemoteException
	 * @return if connection was established
	 */
	public boolean connectFromRMI(String receiverID, int port) throws RemoteException;
}


<|start_filename|>test/matlabcontrol/MatlabRequired.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowEvent;
import java.util.concurrent.atomic.AtomicReference;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import org.junit.Assert;

public class MatlabRequired {
	/** Marks that this test requires user-in-the-loop interaction with MATLAB. */
	public static class Interactive {
		/** Opens a dialog with the given instructions.  Returns a runnable which closes the dialog. */
		public static Runnable prompt(final String instructions) {
			// figure out the name of the test from the stack
			StackTraceElement[] elements = new Throwable().getStackTrace();
			String testName = "unknown";
			for (int i = 1; i < elements.length; ++i) {
				if (!elements[i].getClassName().startsWith("matlabcontrol.")) {
					StackTraceElement element = elements[i - 1];
					testName = element.getClassName() + "::" + element.getMethodName();
					break;
				}
			}
			final String finalTestName = testName;

			// open a dialog and save it
			final AtomicReference<JFrame> box = new AtomicReference<JFrame>();
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					JFrame frame = new JFrame();
					box.set(frame);
					frame.setTitle(finalTestName);

					Container contentPane = frame.getContentPane();
					contentPane.setLayout(new BorderLayout());

					JTextArea label = new JTextArea();
					label.setText(instructions);
					contentPane.add(label, BorderLayout.CENTER);

					JButton button = new JButton();
					button.setText("Fail");
					contentPane.add(button, BorderLayout.SOUTH);

					frame.pack();
					frame.setVisible(true);

					button.addActionListener(new java.awt.event.ActionListener() {
						@Override
						public void actionPerformed(java.awt.event.ActionEvent evt) {
							Assert.fail("User clicked fail");
						}
					});
				}
			});

			// return a runnable which will close the dialog
			return new Runnable() {
				@Override
				public void run() {
					SwingUtilities.invokeLater(new Runnable() {
						@Override
						public void run() {
							JFrame frame = box.get();
							if (frame.isVisible()) {
								frame.setVisible(false);
								;
								frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
							}
						}
					});
				}
			};
		}
	}

	/** Marks that this test requires MATLAB but no user. */
	public static class Headless {}
}


<|start_filename|>src/matlabcontrol/link/MatlabDouble.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * MATLAB {@code double} with real and imaginary components.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabDouble extends MatlabNumber<Double> {
	private static final Double DEFAULT = 0.0d;

	public MatlabDouble(double real, double imag) {
		super(DEFAULT, real, imag);
	}

	/**
	 * Returns the real value.
	 * 
	 * @return 
	 */
	public double toReal() {
		return _real;
	}

	/**
	 * Returns the imaginary value.
	 * 
	 * @return 
	 */
	public double toImaginary() {
		return _imag;
	}
}


<|start_filename|>src/matlabcontrol/link/Linker.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxy.MatlabThreadCallable;
import matlabcontrol.MatlabProxy.MatlabThreadProxy;
import matlabcontrol.link.ArrayMultidimensionalizer.PrimitiveArrayGetter;
import matlabcontrol.link.MatlabFunctionHandle.MatlabFunctionHandleGetter;
import matlabcontrol.link.MatlabNumber.MatlabNumberGetter;
import matlabcontrol.link.MatlabNumberArray.MatlabNumberArrayGetter;
import matlabcontrol.link.MatlabType.MatlabTypeGetter;
import matlabcontrol.link.MatlabType.MatlabTypeSetter;
import matlabcontrol.link.MatlabVariable.MatlabVariableGetter;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public class Linker {
	private Linker() {}

	/**************************************************************************************************************\
	|*                                        Linking & Validation                                                *|
	\**************************************************************************************************************/

	static MatlabOperations getLinkedMatlabOperations(MatlabProxy proxy) {
		if (proxy == null) {
			throw new NullPointerException("proxy may not be null");
		}

		Class<?> opsClass = MatlabOperations.class;
		MatlabOperations operations = (MatlabOperations) Proxy.newProxyInstance(opsClass.getClassLoader(),
				new Class<?>[]{opsClass},
				new MatlabFunctionInvocationHandler(proxy, opsClass, new ConcurrentHashMap<Method, InvocationInfo>()));

		return operations;
	}

	public static <T> T link(Class<T> functionInterface, MatlabProxy proxy) {
		if (!functionInterface.isInterface()) {
			throw new LinkingException(functionInterface.getCanonicalName() + " is not an interface");
		}

		if (proxy == null) {
			throw new NullPointerException("proxy may not be null");
		}

		//Maps each method to information about the function and method
		ConcurrentMap<Method, InvocationInfo> resolvedInfo = new ConcurrentHashMap<Method, InvocationInfo>();

		//Validate and retrieve information about all of the methods in the interface
		for (Method method : functionInterface.getMethods()) {
			//Check method is annotated with function information
			MatlabFunction annotation = method.getAnnotation(MatlabFunction.class);
			if (annotation == null) {
				throw new LinkingException(method + " is not annotated with " +
						MatlabFunction.class.getCanonicalName());
			}

			//Check method can throw MatlabInvocationException
			checkExceptions(method);

			//Store information about how to invoke the method, performing validation in the process
			resolvedInfo.put(method, InvocationInfo.getInvocationInfo(method, annotation));
		}

		T functionProxy = (T) Proxy.newProxyInstance(functionInterface.getClassLoader(),
				new Class<?>[]{functionInterface},
				new MatlabFunctionInvocationHandler(proxy, functionInterface, resolvedInfo));

		return functionProxy;
	}

	private static void checkExceptions(Method method) {
		boolean assignable = false;
		Type[] genericExceptions = method.getGenericExceptionTypes();
		for (Type exception : genericExceptions) {
			if (exception instanceof Class && ((Class<?>) exception).isAssignableFrom(MatlabInvocationException.class)) {
				assignable = true;
			}
		}

		if (!assignable) {
			throw new LinkingException(method + " is not capable of throwing " +
					MatlabInvocationException.class.getCanonicalName() + " or does so with generics");
		}
	}

	/**************************************************************************************************************\
	|*                                        Function Invocation                                                 *|
	\**************************************************************************************************************/

	private static class MatlabFunctionInvocationHandler implements InvocationHandler {
		private final MatlabProxy _proxy;
		private final Class<?> _interface;
		private final ConcurrentMap<Method, InvocationInfo> _invocationsInfo;

		private MatlabFunctionInvocationHandler(MatlabProxy proxy, Class<?> functionInterface,
				ConcurrentMap<Method, InvocationInfo> invocationInfo) {
			_proxy = proxy;
			_interface = functionInterface;
			_invocationsInfo = invocationInfo;
		}

		@Override
		public Object invoke(Object o, Method method, Object[] args) throws MatlabInvocationException {
			Object result;

			//Method belongs to java.lang.Object
			if (method.getDeclaringClass().equals(Object.class)) {
				result = invokeObjectMethod(method, args);
			}
			//Methods defined in matlabcontrol.MatlabOperations interface
			else if (method.getDeclaringClass().equals(MatlabOperations.class)) {
				result = invokeMatlabOperationsMethod(method, args);
			}
			//Method belongs to the interface supplied to this linker
			else {
				result = invokeUserInterfaceMethod(method, args);
			}

			return result;
		}

		private Object invokeObjectMethod(Method method, Object[] args) {
			Object result;

			//public void String toString()
			if (method.getName().equals("toString")) {
				result = "[Linked " + _interface.getCanonicalName() + " info=" + _invocationsInfo + "]";
			}
			//public boolean equals(Object other)
			else if (method.getName().equals("equals")) {
				Object other = args[0];
				if (other != null && Proxy.isProxyClass(other.getClass()) &&
						(Proxy.getInvocationHandler(other) instanceof MatlabFunctionInvocationHandler)) {
					InvocationHandler handler = Proxy.getInvocationHandler(other);
					result = _interface.equals(((MatlabFunctionInvocationHandler) handler)._interface);
				} else {
					result = false;
				}
			}
			//public int hashCode()
			else if (method.getName().equals("hashCode")) {
				result = _interface.hashCode();
			}
			//The other methods of java.lang.Object should not be sent to this invocation handler
			else {
				throw new UnsupportedOperationException(method + " not supported");
			}

			return result;
		}

		private Object invokeMatlabOperationsMethod(Method method, Object[] args) throws MatlabInvocationException {
			Class<?> methodReturn = method.getReturnType();
			Object result;

			if (method.getName().equals("eval")) {
				InvocationInfo info = new InvocationInfo("eval", null, new Class<?>[0], new Class<?>[0][0]);

				result = invokeMatlabFunction(info, false, args, methodReturn);
			} else if (method.getName().equals("returningEval")) {
				//Each return type
				int nargout = (Integer) args[1];
				Class<?>[] returnTypes = new Class<?>[nargout];
				Arrays.fill(returnTypes, Object.class);

				InvocationInfo info = new InvocationInfo("eval", null, returnTypes, new Class<?>[nargout][0]);

				result = invokeMatlabFunction(info, false, new Object[]{args[0]}, methodReturn);
			} else if (method.getName().equals("feval")) {
				//Make function arguments at the same level as the function name
				Object[] functionArgs = (Object[]) args[1];
				Object[] firstLevelArgs = new Object[functionArgs.length + 1];
				firstLevelArgs[0] = args[0];
				System.arraycopy(functionArgs, 0, firstLevelArgs, 1, functionArgs.length);

				InvocationInfo info = new InvocationInfo("feval", null, new Class<?>[0], new Class<?>[0][0]);

				result = invokeMatlabFunction(info, false, firstLevelArgs, methodReturn);
			} else if (method.getName().equals("returningFeval")) {
				//Make function arguments at same level as function name
				Object[] functionArgs = (Object[]) args[2];
				Object[] firstLevelArgs = new Object[functionArgs.length + 1];
				firstLevelArgs[0] = args[0];
				System.arraycopy(functionArgs, 0, firstLevelArgs, 1, functionArgs.length);

				//Each return type
				int nargout = (Integer) args[1];
				Class<?>[] returnTypes = new Class<?>[nargout];
				Arrays.fill(returnTypes, Object.class);

				InvocationInfo info = new InvocationInfo("feval", null, returnTypes, new Class<?>[nargout][0]);

				result = invokeMatlabFunction(info, false, firstLevelArgs, methodReturn);
			} else if (method.getName().equals("getVariable")) {
				InvocationInfo info = new InvocationInfo("eval", null, new Class<?>[]{Object.class}, new Class<?>[1][0]);

				result = ((Object[]) invokeMatlabFunction(info, false, args, methodReturn))[0];
			} else if (method.getName().equals("setVariable")) {
				InvocationInfo info = new InvocationInfo("assignin", null, new Class<?>[0], new Class<?>[0][0]);

				result = invokeMatlabFunction(info, false, new Object[]{"base", args[0], args[1]}, methodReturn);
			} else {
				throw new UnsupportedOperationException(method + " not supported");
			}

			return result;
		}

		private Object invokeUserInterfaceMethod(Method method, Object[] args) throws MatlabInvocationException {
			InvocationInfo info = _invocationsInfo.get(method);

			if (args == null) {
				args = new Object[0];
			}

			//If the method uses var args then we need to make those arguments first level
			if (method.isVarArgs() && args.length > 0) {
				Object varArgs = args[args.length - 1];
				if (varArgs.getClass().isArray()) {
					//Number of variable arguments
					int varArgLength = Array.getLength(varArgs);

					//Combined arguments, ignoring the last argument which was the var arg array container
					Object[] allArgs = new Object[args.length + varArgLength - 1];
					System.arraycopy(args, 0, allArgs, 0, args.length - 1);

					//Update information with var args as first level arguments
					for (int i = 0; i < varArgLength; i++) {
						Object arg = Array.get(varArgs, i);
						allArgs[i + args.length - 1] = arg;
					}
					args = allArgs;
				}
			}

			return invokeMatlabFunction(info, true, args, method.getReturnType());
		}

		private Object invokeMatlabFunction(InvocationInfo info, boolean userDefined, Object[] args,
				Class<?> methodReturn)
				throws MatlabInvocationException {
			//Replace all arguments with parameters of a MatlabType subclass or a multidimensional primitive array with
			//their serialized setters
			for (int i = 0; i < args.length; i++) {
				if (args[i] != null) {
					ClassInfo argInfo = ClassInfo.getInfo(args[i].getClass());

					if (argInfo.isMatlabType) {
						args[i] = ((MatlabType) args[i]).getSetter();
					} else if (argInfo.isPrimitiveArray) {
						args[i] = ArrayLinearizer.getSetter(args[i]);
					}
				}
			}

			//Invoke function
			FunctionResult result = _proxy.invokeAndWait(new CustomFunctionInvocation(info, args));
			if (result.thrownException != null) {
				result.thrownException.fillInStackTrace();
				throw result.thrownException;
			}
			Object[] returnValues = result.returnArgs;

			//For each returned value that is a serialized getter, retrieve it
			for (int i = 0; i < returnValues.length; i++) {
				if (returnValues[i] instanceof MatlabTypeGetter) {
					returnValues[i] = ((MatlabType.MatlabTypeGetter) returnValues[i]).retrieve();
				}
			}

			//Process returned values if user defined
			Object toReturn;
			if (userDefined) {
				toReturn = processReturnValues(info, returnValues, methodReturn);
			} else {
				toReturn = returnValues;
			}

			return toReturn;
		}

		private Object processReturnValues(InvocationInfo info, Object[] result, Class<?> methodReturn) {
			Object toReturn;
			//0 return values
			if (result.length == 0) {
				toReturn = result;
			}
			//1 return values
			else if (result.length == 1) {
				toReturn = validateAssignability(result[0], info.returnTypes[0], info.returnTypeParameters[0]);
			}
			//2 or more return values
			else {
				for (int i = 0; i < result.length; i++) {
					result[i] = validateAssignability(result[i], info.returnTypes[i], info.returnTypeParameters[0]);
				}

				toReturn = MatlabReturns.getMaxReturn(result);
			}

			return toReturn;
		}

		private Object validateAssignability(Object value, Class<?> returnType, Class<?>[] returnTypeParameters) {
			Object toReturn;
			if (value == null) {
				if (returnType.isPrimitive()) {
					throw new UnassignableReturnException("Return type is primitive and cannot be assigned null\n" +
							"Return type: " + toClassString(returnType, returnTypeParameters));
				} else {
					toReturn = null;
				}
			} else if (returnType.isPrimitive()) {
				Class<?> autoboxedClass = PRIMITIVE_TO_AUTOBOXED.get(returnType);
				if (autoboxedClass.equals(value.getClass())) {
					toReturn = value;
				} else {
					throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
							"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
							"Value type:  " + toClassString(value));
				}
			} else {
				if (!returnType.isAssignableFrom(value.getClass())) {
					throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
							"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
							"Value type:  " + toClassString(value));
				}

				//If the return type is a MatlabNumberArray subclass
				if (MatlabNumberArray.class.isAssignableFrom(returnType)) {
					//Check the parameterization matches
					if (!((MatlabNumberArray) value).getOutputArrayType().equals(returnTypeParameters[0])) {
						throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
								"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
								"Value type:  " + toClassString(value));
					}
				}

				toReturn = value;
			}

			return toReturn;
		}

		private static String toClassString(Class<?> returnType, Class<?>[] returnTypeParameters) {
			StringBuilder classString = new StringBuilder();
			classString.append(returnType.getCanonicalName());

			if (returnTypeParameters.length != 0) {
				classString.append("<");

				for (int i = 0; i < returnTypeParameters.length; i++) {
					classString.append(returnTypeParameters[i].getCanonicalName());

					if (i != returnTypeParameters.length - 1) {
						classString.append(", ");
					}
				}

				classString.append(">");
			}

			return classString.toString();
		}

		private static String toClassString(Object obj) {
			String classString;

			if (obj == null) {
				classString = "null";
			} else if (MatlabNumberArray.class.isAssignableFrom(obj.getClass())) {
				MatlabNumberArray array = (MatlabNumberArray) obj;
				classString = array.getClass().getCanonicalName() +
						"<" + array.getOutputArrayType().getCanonicalName() + ">";
			} else {
				classString = obj.getClass().getCanonicalName();
			}

			return classString;
		}

		private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_AUTOBOXED;

		static {
			Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();

			map.put(byte.class, Byte.class);
			map.put(short.class, Short.class);
			map.put(int.class, Integer.class);
			map.put(long.class, Long.class);
			map.put(double.class, Double.class);
			map.put(float.class, Float.class);
			map.put(boolean.class, Boolean.class);
			map.put(char.class, Character.class);

			PRIMITIVE_TO_AUTOBOXED = Collections.unmodifiableMap(map);
		}
	}

	private static class FunctionResult implements Serializable {
		private static final long serialVersionUID = -5636384730122824487L;
		private final Object[] returnArgs;
		private final RuntimeException thrownException;

		FunctionResult(Object[] returnArgs) {
			this.returnArgs = returnArgs;
			this.thrownException = null;
		}

		FunctionResult(RuntimeException thrownException) {
			this.returnArgs = null;
			this.thrownException = thrownException;
		}
	}

	private static class CustomFunctionInvocation implements MatlabThreadCallable<FunctionResult>, Serializable {
		private static final long serialVersionUID = -7108052527648813829L;
		private final InvocationInfo _functionInfo;
		private final Object[] _args;

		private CustomFunctionInvocation(InvocationInfo functionInfo, Object[] args) {
			_functionInfo = functionInfo;
			_args = args;
		}

		@Override
		public FunctionResult call(MatlabThreadProxy proxy) throws MatlabInvocationException {
			FunctionResult result;
			try {
				result = new FunctionResult(this.invoke(proxy));
			} catch (RuntimeException e) {
				result = new FunctionResult(e);
			}

			return result;
		}

		private Object[] invoke(MatlabOperations ops) throws MatlabInvocationException {
			String initialDir = null;

			//If the function was specified as not being on MATLAB's path
			if (_functionInfo.containingDirectory != null) {
				//Initial directory before cding
				initialDir = (String) ops.returningFeval("pwd", 1)[0];

				//No need to change directory
				if (initialDir.equals(_functionInfo.containingDirectory)) {
					initialDir = null;
				}
				//Change directory to where the function is located
				else {
					ops.feval("cd", _functionInfo.containingDirectory);
				}
			}

			List<String> variablesToClear = new ArrayList<String>();
			try {
				//Set all arguments as MATLAB variables and build a function call using those variables
				StringBuilder functionStr = new StringBuilder();
				functionStr.append(_functionInfo.name + "(");
				List<String> parameterNames = generateNames(ops, "param_", _args.length);
				for (int i = 0; i < _args.length; i++) {
					String name = parameterNames.get(i);
					variablesToClear.add(name);

					setReturnValue(ops, name, _args[i]);

					functionStr.append(name);
					if (i != _args.length - 1) {
						functionStr.append(", ");
					}
				}
				functionStr.append(");");

				//Return arguments
				List<String> returnNames = null;
				if (_functionInfo.returnTypes.length != 0) {
					returnNames = generateNames(ops, "return_", _functionInfo.returnTypes.length);
					StringBuilder returnStr = new StringBuilder();
					returnStr.append("[");
					for (int i = 0; i < returnNames.size(); i++) {
						ClassInfo returnInfo = ClassInfo.getInfo(_functionInfo.returnTypes[i]);

						String name;
						if (returnInfo.isVoid) {
							name = "~";
						} else {
							name = returnNames.get(i);
							variablesToClear.add(name);
						}

						returnStr.append(name);
						if (i != returnNames.size() - 1) {
							returnStr.append(", ");
						}
					}
					returnStr.append("] = ");

					functionStr.insert(0, returnStr);
				}

				//Invoke the function
				ops.eval(functionStr.toString());

				//Get the return values
				List<String> variablesToKeep = new ArrayList<String>();
				Object[] returnValues = new Object[_functionInfo.returnTypes.length];
				for (int i = 0; i < returnValues.length; i++) {
					ClassInfo returnInfo = ClassInfo.getInfo(_functionInfo.returnTypes[i]);

					//No return
					if (returnInfo.isVoid) {
						returnValues[i] = null;
					}
					//Not a true "return", keeps the value in MATLAB and returns the name of the variable
					else if (_functionInfo.returnTypes[i].equals(MatlabVariable.class)) {
						MatlabVariableGetter getter = new MatlabVariableGetter();
						getter.getInMatlab(ops, returnNames.get(i));
						returnValues[i] = getter;

						variablesToKeep.add(returnNames.get(i));
					}
					//Retrieve the value
					else {
						returnValues[i] = getReturnValue(ops, returnNames.get(i), returnInfo,
								_functionInfo.returnTypeParameters[i], variablesToClear);
					}
				}

				//Do this last, so if any exceptions occurred then the variables will not be kept
				variablesToClear.removeAll(variablesToKeep);

				return returnValues;
			}
			//Restore MATLAB's state to what it was before the function call happened
			finally {
				try {
					//Clear all variables used
					if (!variablesToClear.isEmpty()) {
						StringBuilder clearCmd = new StringBuilder();
						clearCmd.append("clear ");
						for (int i = 0; i < variablesToClear.size(); i++) {
							clearCmd.append(variablesToClear.get(i));

							if (i != variablesToClear.size() - 1) {
								clearCmd.append(" ");
							}
						}
						ops.eval(clearCmd.toString());
					}
				} finally {
					//If necessary, change back to the directory MATLAB was in before the function was invoked
					if (initialDir != null) {
						ops.feval("cd", initialDir);
					}
				}
			}
		}

		private static void setReturnValue(MatlabOperations ops, String name, Object arg)
				throws MatlabInvocationException {
			if (arg == null) {
				ops.eval(name + " = [];");
			} else if (arg instanceof MatlabTypeSetter) {
				((MatlabTypeSetter) arg).setInMatlab(ops, name);
			} else if (ClassInfo.getInfo(arg.getClass()).isBuiltinNumeric) {
				Number number = (Number) arg;

				if (number instanceof Byte) {
					ops.eval(name + "=int8(" + number.byteValue() + ");");
				} else if (number instanceof Short) {
					ops.eval(name + "=int16(" + number.shortValue() + ");");
				} else if (number instanceof Integer) {
					ops.eval(name + "=int32(" + number.intValue() + ");");
				} else if (number instanceof Long) {
					ops.eval(name + "=int64(" + number.longValue() + ");");
				} else if (number instanceof Float) {
					ops.setVariable(name, new float[]{number.floatValue()});
				} else if (number instanceof Double) {
					ops.setVariable(name, new double[]{number.doubleValue()});
				}
			} else {
				MatlabValueSetter.setInMatlab(ops, name, arg);
			}
		}

		private static class MatlabValueSetter {
			private static void setInMatlab(MatlabOperations ops, String variableName, Object value)
					throws MatlabInvocationException {
				MatlabValueSetter setter = new MatlabValueSetter(value);
				ops.setVariable(variableName, setter);
				ops.eval(variableName + " = " + variableName + ".getValue();");
			}

			private final Object _value;

			private MatlabValueSetter(Object value) {
				_value = value;
			}

			@SuppressWarnings("unused")
			// called in MATLAB by the script above
			public Object getValue() {
				return _value;
			}
		}

		private static Object getReturnValue(MatlabOperations ops, String returnName, ClassInfo returnInfo,
				Class<?>[] returnParams, List<String> variablesToClear) throws MatlabInvocationException {
			Object returnValue;

			//Empty array, MATLAB's rough equivalent of null
			if (isFoo(ops, "isempty", returnName)) {
				returnValue = null;
			}
			//The variable is a Java object
			else if (isFoo(ops, "isjava", returnName)) {
				returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
			} else {
				String type = (String) ops.returningEval("class(" + returnName + ");", 1)[0];

				if (type.equals("function_handle")) {
					MatlabFunctionHandleGetter getter = new MatlabFunctionHandleGetter();
					getter.getInMatlab(ops, returnName);
					returnValue = getter;
				} else if (MATLAB_TO_JAVA_PRIMITIVE.containsKey(type)) {
					//If a singular value
					boolean isScalar = isFoo(ops, "isscalar", returnName);

					//Whether the value should be returned as a linear array instead of MATLAB's default of the minimum
					//array dimension being 2
					boolean keepLinear = false;
					if (!isScalar) {
						if (MatlabNumberArray.class.isAssignableFrom(returnInfo.describedClass)) {
							ClassInfo returnParamInfo = ClassInfo.getInfo(returnParams[0]);
							keepLinear = returnParamInfo.arrayDimensions == 1 && isFoo(ops, "isvector", returnName);
						} else {
							keepLinear = returnInfo.arrayDimensions == 1 && isFoo(ops, "isvector", returnName);
						}
					}

					//logical -> boolean
					if (type.equals("logical")) {
						if (isScalar) {
							returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
						} else {
							PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
							getter.getInMatlab(ops, returnName);
							returnValue = getter;
						}
					}
					//char -> char or String
					else if (type.equals("char")) {
						//If the return type is specified as char, Character, or an array of char
						if (char.class.equals(returnInfo.describedClass) || Character.class.equals(returnInfo.describedClass) ||
								char.class.equals(returnInfo.baseComponentType)) {
							if (isScalar) {
								returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
							} else {
								PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
								getter.getInMatlab(ops, returnName);
								returnValue = getter;
							}
						}
						//By default retrieve it as a String or an array of Strings
						else {
							returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
						}
					}
					//Numerics
					//int8 -> byte, int16 -> short, int32 -> int, int64 -> long, single -> float, double -> double
					else {
						boolean isReal = isFoo(ops, "isreal", returnName);

						//Singular value
						if (isScalar) {
							//If the return value is real and the return type is a primitive numeric or the autobox
							if (isReal && returnInfo.isBuiltinNumeric) {
								returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
							}
							//By default, return a MatlabNumber
							else {
								MatlabNumberGetter getter = new MatlabNumberGetter();
								getter.getInMatlab(ops, returnName);
								returnValue = getter;
							}
						}
						//Array
						else {
							//If the return value is a real array and the return type is a primitive numeric array
							if (isReal && returnInfo.isArray && returnInfo.baseComponentType.isPrimitive() &&
									ClassInfo.getInfo(returnInfo.baseComponentType).isBuiltinNumeric) {
								PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
								getter.getInMatlab(ops, returnName);
								returnValue = getter;
							}
							//By default, return a MatlabNumberArray
							else {
								MatlabNumberArrayGetter getter = new MatlabNumberArrayGetter(keepLinear);
								getter.getInMatlab(ops, returnName);
								returnValue = getter;
							}
						}
					}
				} else {
					throw new UnsupportedReturnException("Unsupported MATLAB type: " + type);
				}
			}

			return returnValue;
		}

		/**
		 * Convenience method to invoke a MATLAB "is" function; equivalent to {@code function(var);}
		 * 
		 * @param ops
		 * @param function
		 * @param var
		 * @return
		 * @throws MatlabInvocationException 
		 */
		private static boolean isFoo(MatlabOperations ops, String function, String var) throws MatlabInvocationException {
			return ((boolean[]) ops.returningEval(function + "(" + var + ");", 1)[0])[0];
		}

		private static final Map<String, Class<?>> MATLAB_TO_JAVA_PRIMITIVE;

		static {
			Map<String, Class<?>> map = new HashMap<String, Class<?>>();

			map.put("int8", byte.class);
			map.put("int16", short.class);
			map.put("int32", int.class);
			map.put("int64", long.class);
			map.put("single", float.class);
			map.put("double", double.class);
			map.put("logical", boolean.class);
			map.put("char", char.class);

			MATLAB_TO_JAVA_PRIMITIVE = Collections.unmodifiableMap(map);
		}

		private static class MatlabValueReceiver {
			private static Object receiveValue(MatlabOperations ops, List<String> variablesToClear, String variableName)
					throws MatlabInvocationException {
				String receiverName = (String) ops.returningEval("genvarname('receiver_', who);", 1)[0];
				MatlabValueReceiver receiver = new MatlabValueReceiver();
				ops.setVariable(receiverName, receiver);
				variablesToClear.add(receiverName);
				ops.eval(receiverName + ".set(" + variableName + ");");

				return receiver._value;
			}

			private Object _value = null;

			@SuppressWarnings("unused")
			// called in MATLAB by the script above
			public void set(Object val) {
				_value = val;
			}
		}

		private List<String> generateNames(MatlabOperations ops, String root, int amount)
				throws MatlabInvocationException {
			//Build set of currently taken names
			Set<String> takenNames = new HashSet<String>(Arrays.asList((String[]) ops.returningEval("who", 1)[0]));

			//Generate names
			List<String> generatedNames = new ArrayList<String>();
			int genSequenence = 0;
			while (generatedNames.size() != amount) {
				String generatedName = root + genSequenence;
				while (takenNames.contains(generatedName)) {
					genSequenence++;
					generatedName = root + genSequenence;
				}
				genSequenence++;
				generatedNames.add(generatedName);
			}

			return generatedNames;
		}
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabFunctionHandle.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.HashSet;
import java.util.Set;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabFunctionHandle extends MatlabType {
	private final String _function;

	public MatlabFunctionHandle(String functionName) {
		if (functionName == null) {
			throw new NullPointerException("MATLAB function name may not be null");
		}

		if (functionName.isEmpty()) {
			throw new IllegalArgumentException("Invalid MATLAB function name; may not be an empty String");
		}

		//Anonymous function
		if (functionName.startsWith("@")) {
			checkAnonymousFunction(functionName);
		}
		//Regular function
		else {
			checkFunctionName(functionName);
		}

		_function = functionName;
	}

	private static void checkAnonymousFunction(String function) {
		char[] functionChars = function.toCharArray();

		//Validate that the the anonymous function is of the form @(something)
		if (functionChars.length < 2 || functionChars[1] != '(') {
			throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
					"@ must be followed with (");
		}
		int closingParenIndex = function.indexOf(")");
		if (closingParenIndex == -1) {
			throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
					"Must terminate the argument list with )");
		}

		//Validate all of the arguments of the anonymous function
		String argsString = function.substring(2, closingParenIndex);
		String[] args;
		args = argsString.isEmpty() ? new String[0] : argsString.split(", ");
		Set<String> seenArgs = new HashSet<String>();
		for (String arg : args) {
			arg = arg.trim();

			if (seenArgs.contains(arg)) {
				throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
						"Invalid argument name: " + arg + "\n" +
						"Argument names must be unique");
			}
			seenArgs.add(arg);

			char[] argsChars = arg.toCharArray();

			if (!Character.isLetter(argsChars[0])) {
				throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
						"Invalid argument name: " + arg + "\n" +
						"Argument must begin with a letter");
			}

			for (char element : argsChars) {
				if (!(Character.isLetter(element) || Character.isDigit(element) || element == '_')) {
					throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
							"Invalid argument name: " + arg + "\n" +
							"Argument must consist only of letters, numbers, and underscores");
				}
			}
		}

		//Validate the function has a body, but don't actually validate the body
		String body = function.substring(closingParenIndex + 1, function.length());
		if (body.trim().isEmpty()) {
			throw new IllegalArgumentException("Invalid anonymous MATLAB function: " + function + "\n" +
					"Anonymous function must have a body");
		}
	}

	private static void checkFunctionName(String functionName) {
		char[] nameChars = functionName.toCharArray();

		if (!Character.isLetter(nameChars[0])) {
			throw new IllegalArgumentException("Invalid MATLAB function name: " + functionName + "\n" +
					"Function name must begin with a letter");
		}

		for (char element : nameChars) {
			if (!(Character.isLetter(element) || Character.isDigit(element) || element == '_')) {
				throw new IllegalArgumentException("Invalid MATLAB function name: " + functionName + "\n" +
						"Function name must consist only of letters, numbers, and underscores");
			}
		}
	}

	@Override
	public String toString() {
		return "[" + this.getClass().getName() + " functionName=" + _function + "]";
	}

	@Override
	MatlabTypeSetter getSetter() {
		return new MatlabFunctionHandlerSetter(_function);
	}

	private static class MatlabFunctionHandlerSetter implements MatlabTypeSetter {
		private static final long serialVersionUID = 1909686398012439080L;
		private final String _function;

		public MatlabFunctionHandlerSetter(String function) {
			_function = function;
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			if (_function.startsWith("@")) {
				ops.eval(variableName + " = " + _function + ";");
			} else {
				ops.eval(variableName + " = @" + _function + ";");
			}
		}
	}

	static class MatlabFunctionHandleGetter implements MatlabTypeGetter<MatlabFunctionHandle> {
		private static final long serialVersionUID = 4448554689248088229L;
		private String _function;
		private boolean _retrieved = false;

		@Override
		public MatlabFunctionHandle retrieve() {
			if (_retrieved) {
				return new MatlabFunctionHandle(_function);
			} else {
				throw new IllegalStateException("MatlabFunctionHandle cannot be deserialized until the data has been " +
						"retrieved from MATLAB");
			}
		}

		@Override
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			_function = (String) ops.returningEval("func2str(" + variableName + ");", 1)[0];

			_retrieved = true;
		}
	}
}


<|start_filename|>src/matlabcontrol/MatlabConnector.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import matlabcontrol.MatlabProxy.MatlabThreadCallable;
import matlabcontrol.MatlabProxy.MatlabThreadProxy;
import matlabcontrol.internal.MatlabRMIClassLoaderSpi;

/**
 * This class is used only from inside of the MATLAB JVM. It is responsible for creating instances of
 * {@link JMIWrapperRemote} and sending them to a waiting receiver over RMI.
 * <br><br>
 * While this class is package private, it can be seen by MATLAB, which does not respect the package privateness of the
 * class. The public methods in this class can be accessed from inside the MATLAB environment.
 * 
 * @since 3.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabConnector {
	/**
	 * Used to establish connections on a separate thread.
	 */
	private static final ExecutorService _connectionExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("MLC Connection Establisher"));

	/**
	 * The most recently connected receiver retrieved from a Java program running outside of MATLAB.
	 */
	private static final AtomicReference<RequestReceiver> _receiverRef = new AtomicReference<RequestReceiver>();

	/**
	 * If a connection is currently in progress.
	 */
	private static final AtomicBoolean _connectionInProgress = new AtomicBoolean(false);

	/**
	 * Private constructor so this class cannot be constructed.
	 */
	private MatlabConnector() {}

	private static class NamedThreadFactory implements ThreadFactory {
		private static final AtomicInteger COUNTER = new AtomicInteger();

		private final String _name;

		NamedThreadFactory(String name) {
			_name = name;
		}

		@Override
		public Thread newThread(Runnable r) {
			return new Thread(r, _name + "-" + COUNTER.getAndIncrement());
		}
	}

	/**
	 * If this session of MATLAB is available to be connected to from an external Java program. It will be available if
	 * it is not currently connected to and there is no connection in progress.
	 * 
	 * @return 
	 */
	static boolean isAvailableForConnection() {
		boolean available;

		if (_connectionInProgress.get()) {
			available = false;
		} else {
			RequestReceiver receiver = _receiverRef.get();

			boolean connected = false;
			if (receiver != null) {
				try {
					receiver.getReceiverID();
					connected = true;
				} catch (RemoteException e) {}
			}

			available = !connected;
		}

		return available;
	}

	/**
	 * Called from MATLAB at launch. Creates the JMI wrapper and then sends it over RMI to the Java program running in a
	 * separate JVM.
	 * 
	 * @param receiverID the key that binds the receiver in the registry
	 * @param port the port the registry is running on
	 * @param initializationTime
	 */
	public static void connectFromMatlab(String receiverID, int port) {
		connect(receiverID, port, false);
	}

	/**
	 * Retrieves the receiver and sends over the {@link JMIWrapperRemote} on a separate thread so that MATLAB can
	 * continue to initialize.
	 * 
	 * @param receiverID
	 * @param port
	 * @param existingSession 
	 */
	static void connect(String receiverID, int port, boolean existingSession) {
		_connectionInProgress.set(true);

		//Establish the connection on a separate thread to allow MATLAB to continue to initialize
		//(If this request is coming over RMI then MATLAB has already initialized, but this will not cause an issue.)
		_connectionExecutor.submit(new EstablishConnectionRunnable(receiverID, port, existingSession));
	}

	/**
	 * A runnable which sets up matlabcontrol inside MATLAB and sends over the remote JMI wrapper.
	 */
	private static class EstablishConnectionRunnable implements Runnable {
		private final String _receiverID;
		private final int _port;
		private final boolean _existingSession;

		/**
		 * The classpath (with each classpath entry as an individual canonical path) of the most recently connected
		 * receiver's JVM.
		 * <br><br>
		 * This variable can safely be volatile because the needed behavior is volatile read/write of the array, not
		 * its entries. It is also unlikely the volatile behavior is actually necessary, but it could be if the thread
		 * used by {@link MatlabConnector#_connectionExecutor} died and created a new one - this ensures visibility.
		 */
		private static volatile String[] _previousRemoteClassPath = new String[0];

		private EstablishConnectionRunnable(String receiverID, int port, boolean existingSession) {
			_receiverID = receiverID;
			_port = port;
			_existingSession = existingSession;
		}

		@Override
		public void run() {
			//Validate matlabcontrol can be used
			try {
				JMIValidator.validateJMIMethods();
			} catch (MatlabConnectionException ex) {
				System.err.println("matlabcontrol is not compatible with this version of MATLAB");
				ex.printStackTrace();
				return;
			}

			//If MATLAB was just launched
			if (!_existingSession) {
				//Set the RMI class loader service provider
				System.setProperty("java.rmi.server.RMIClassLoaderSpi", MatlabRMIClassLoaderSpi.class.getName());

				//Make this session of MATLAB of visible over RMI so that reconnections can occur, proceed if it fails
				try {
					MatlabBroadcaster.broadcast(_port);
				} catch (MatlabConnectionException ex) {
					System.err.println("Reconnecting to this session of MATLAB will not be possible");
					ex.printStackTrace();
				}
			}

			//Send the remote JMI wrapper
			try {
				//Get registry
				Registry registry = LocalHostRMIHelper.getRegistry(_port);

				//Get the receiver from the registry, if it cannot be retrieved, retry once after waiting.
				//The retry is attempted because the factory checks periodically to see if the receiver is bound and
				//will attempt a rebind if it is not.
				RequestReceiver receiver;
				try {
					receiver = (RequestReceiver) registry.lookup(_receiverID);
				} catch (NotBoundException nbe1) {
					try {
						Thread.sleep(RemoteMatlabProxyFactory.RECEIVER_CHECK_PERIOD);

						try {
							receiver = (RequestReceiver) registry.lookup(_receiverID);
						} catch (NotBoundException nbe2) {
							System.err.println("First attempt to connect to Java application failed");
							nbe1.printStackTrace();
							System.err.println("Second attempt to connect to Java application failed");
							nbe2.printStackTrace();
							return;
						}
					} catch (InterruptedException ie) {
						System.err.println("First attempt to connect to Java application failed");
						nbe1.printStackTrace();
						System.err.println("Interrupted while waiting to retry connection to Java application");
						ie.printStackTrace();
						return;
					}
				}

				//Hold on the to receiver
				_receiverRef.set(receiver);

				//Load a security manager so that remote class loading can occur
				if (System.getSecurityManager() == null) {
					System.setSecurityManager(new PermissiveSecurityManager());
				}

				//Tell the RMI class loader of the codebase where the receiver is from, this will allow MATLAB to load
				//classes defined in the remote JVM, but not in this one
				MatlabRMIClassLoaderSpi.setCodebase(receiver.getClassPathAsRMICodebase());

				//Tell MATLAB's class loader about the codebase where the receiver is from, if not then MATLAB's
				//environment will freak out when interacting with classes it cannot find the definition of and throw
				//exceptions with rather confusing messages
				String[] newClassPath = receiver.getClassPathAsCanonicalPaths();
				try {
					JMIWrapper.invokeAndWait(new ModifyCodebaseCallable(_previousRemoteClassPath, newClassPath));
					_previousRemoteClassPath = newClassPath;
				} catch (MatlabInvocationException e) {
					System.err.println("Unable to update MATLAB's class loader; issues may arise interacting with " +
							"classes not defined in MATLAB's Java Virtual Machine");
					e.printStackTrace();
				}

				//Create the remote JMI wrapper and then pass it over RMI to the Java application in its own JVM
				receiver.receiveJMIWrapper(new JMIWrapperRemoteImpl(), _existingSession);
			} catch (RemoteException ex) {
				System.err.println("Connection to Java application could not be established");
				ex.printStackTrace();
			}

			_connectionInProgress.set(false);
		}
	}

	/**
	 * Modifies MATLAB's dynamic class path. Retrieves the current dynamic class path, removes all of the entries
	 * from the previously connected JVM, adds the new ones, and if the classpath is now different, sets a new dynamic
	 * classpath.
	 */
	private static class ModifyCodebaseCallable implements MatlabThreadCallable<Void> {
		private final String[] _toRemove;
		private final String[] _toAdd;

		public ModifyCodebaseCallable(String[] oldRemoteClassPath, String[] newRemoteClassPath) {
			_toRemove = oldRemoteClassPath;
			_toAdd = newRemoteClassPath;
		}

		@Override
		public Void call(MatlabThreadProxy proxy) throws MatlabInvocationException {
			//Current dynamic class path
			String[] curr = (String[]) proxy.returningFeval("javaclasspath", 1, "-dynamic")[0];

			//Build new dynamic class path
			List<String> newDynamic = new ArrayList<String>();
			newDynamic.addAll(Arrays.asList(curr));
			newDynamic.removeAll(Arrays.asList(_toRemove));
			newDynamic.addAll(Arrays.asList(_toAdd));

			//If the class path is different, set it
			if (!newDynamic.equals(Arrays.asList(curr))) {
				proxy.feval("javaclasspath", new Object[]{newDynamic.toArray(new String[newDynamic.size()])});
			}

			return null;
		}
	}
}


<|start_filename|>test/matlabcontrol/CopyPasteTest.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import matlabcontrol.MatlabProxyFactory.CopyPasteCallback;

import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;

@Category(MatlabRequired.Interactive.class)
public class CopyPasteTest {
	private Runnable runnable;

	@Test
	public void testCopyPaste() throws MatlabConnectionException, MatlabInvocationException {
		MatlabProxyFactoryOptions.Builder builder = new MatlabProxyFactoryOptions.Builder();
		builder.setCopyPasteCallback(new CopyPasteCallback() {
			@Override
			public void copyPaste(String matlabCmdsToConnect) {
				StringBuilder builder = new StringBuilder();
				builder.append("Copy-paste the following lines into a MATLAB:\n");
				String[] pieces = matlabCmdsToConnect.split(";");
				for (String piece : pieces) {
					builder.append("    " + piece.trim() + ";\n");
				}
				builder.append("\nWaiting for you to paste.");
				runnable = MatlabRequired.Interactive.prompt(builder.toString());
			}
		});
		MatlabProxyFactory factory = new MatlabProxyFactory(builder.build());
		MatlabProxy proxy = factory.getProxy();
		try {
			runnable.run();
			proxy.eval("disp('connection established')");
			proxy.setVariable("test", "abc");
			Assert.assertEquals("abc", proxy.getVariable("test"));
		} finally {
			runnable.run();
			proxy.disconnect();
		}
	}
}


<|start_filename|>src/matlabcontrol/link/FullArray.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * 
 * @param <L> underlying linear array - single dimensional array type, ex. {@code byte[]}
 * @param <T> output array - primitive numeric array type, ex. {@code byte[][][]}
 *            (1 or more dimensions is acceptable, including for example {@code byte[]})
 */
class FullArray<L, T> extends BaseArray<L, T> {
	/**
	 * The lengths of each dimension of the array when represented as an array of type {@code T}.
	 */
	final int[] _dimensions;

	/**
	 * The total number of elements represented by this full array. This includes the zero elements represented by
	 * this array. This is equivalent to multiplying all values of {@link #_dimensions} together.
	 */
	private final int _numberOfElements;

	/**
	 * The primitive numeric type stored by the arrays.
	 */
	final Class<?> _baseComponentType;

	/**
	 * Internal linear array type.
	 */
	final Class<L> _linearArrayType;

	/**
	 * Output array type.
	 */
	final Class<T> _outputArrayType;

	/**
	 * The linear array of real values.
	 */
	final L _real;

	/**
	 * The linear array of imaginary values. Can be {@code null} if this number array is real.
	 */
	final L _imag;

	/**
	 * Caches if {@link #_imag} contains non-zero elements.
	 * <br><br>
	 * To avoid any form of inter-thread communication this value may in the most degenerate case be recomputed for each
	 * thread.
	 */
	private Boolean _hasImaginaryValues = null;

	/**
	 * Caches the hash code.
	 * <br><br>
	 * To avoid any form of inter-thread communication this value may in the most degenerate case be recomputed for each
	 * thread.
	 */
	private Integer _hashCode = null;

	/**
	 * Data from MATLAB. Provided as the linear arrays and dimensions.
	 * 
	 * @param linearArrayType
	 * @param realLinear
	 * @param imagLinear
	 * @param dimensions 
	 */
	@SuppressWarnings("unchecked")
	FullArray(Class<L> linearArrayType, L real, L imag, int[] dimensions) {
		//Dimensions of the array
		_dimensions = dimensions;
		_numberOfElements = ArrayUtils.getNumberOfElements(_dimensions);

		//The real and imaginary arrays should always be of type L, but validate it
		_real = linearArrayType.cast(real);
		_imag = linearArrayType.cast(imag);

		//Make class information at run time
		_baseComponentType = linearArrayType.getComponentType();
		_linearArrayType = linearArrayType;
		_outputArrayType = (Class<T>) ArrayUtils.getArrayClass(_baseComponentType, dimensions.length);
	}

	@SuppressWarnings("unchecked")
	FullArray(Class<L> linearArrayType, T real, T imag) {
		//Real array cannot be null
		if (real == null) {
			throw new NullPointerException("Real array may not be null");
		}

		//Make class information at run time
		_baseComponentType = linearArrayType.getComponentType();
		_linearArrayType = linearArrayType;
		_outputArrayType = (Class<T>) real.getClass();

		//Confirm real array is actually an array
		Class<?> realClass = real.getClass();
		if (!realClass.isArray()) {
			throw new IllegalArgumentException("Real array is not an array, type: " + realClass.getCanonicalName());
		}

		//Confirm the real array is of the supported type
		Class<?> realBaseComponentType = ArrayUtils.getBaseComponentType(realClass);
		if (!realBaseComponentType.equals(_baseComponentType)) {
			throw new IllegalArgumentException("Real array is not an array of the required class\n" +
					"Required base component type: " + _baseComponentType.getCanonicalName() + "\n" +
					"Provided base component type: " + realBaseComponentType.getCanonicalName());
		}

		//Confirm the imag array is of the same type as the real array
		if (imag != null && !imag.getClass().equals(realClass)) {
			throw new IllegalArgumentException("Imaginary array is not of the same class as the real array\n" +
					"Real array class: " + realClass.getCanonicalName() + "\n" +
					"Imaginary array class: " + imag.getClass().getCanonicalName());
		}

		//Determine dimensions
		_dimensions = new int[ArrayUtils.getNumberOfDimensions(_outputArrayType)];
		int[] realDimensions = ArrayUtils.computeBoundingDimensions(real);
		for (int i = 0; i < realDimensions.length; i++) {
			_dimensions[i] = Math.max(_dimensions[i], realDimensions[i]);
		}
		if (imag != null) {
			int[] imagDimensions = ArrayUtils.computeBoundingDimensions(imag);
			for (int i = 0; i < imagDimensions.length; i++) {
				_dimensions[i] = Math.max(_dimensions[i], imagDimensions[i]);
			}
		}
		_numberOfElements = ArrayUtils.getNumberOfElements(_dimensions);

		//Linearize arrays
		_real = _linearArrayType.cast(ArrayLinearizer.linearize(real, _dimensions));
		if (imag != null) {
			_imag = _linearArrayType.cast(ArrayLinearizer.linearize(imag, _dimensions));
		} else {
			_imag = null;
			_hasImaginaryValues = false;
		}
	}

	@Override
	int getNumberOfElements() {
		return _numberOfElements;
	}

	@Override
	int getLengthOfDimension(int dimension) {
		if (dimension >= _dimensions.length || dimension < 0) {
			throw new IllegalArgumentException(dimension + " is not a dimension of this array. This array has " +
					getNumberOfDimensions() + " dimensions");
		}

		return _dimensions[dimension];
	}

	@Override
	int getNumberOfDimensions() {
		return _dimensions.length;
	}

	@Override
	boolean isReal() {
		if (_hasImaginaryValues == null) {
			_hasImaginaryValues = ArrayUtils.containsNonDefaultValue(_imag);
		}

		return !_hasImaginaryValues;
	}

	@Override
	T toRealArray() {
		return _outputArrayType.cast(ArrayMultidimensionalizer.multidimensionalize(_real, _dimensions));
	}

	@Override
	T toImaginaryArray() {
		T array;
		if (isReal()) {
			array = _outputArrayType.cast(Array.newInstance(_baseComponentType, _dimensions));
		} else {
			array = _outputArrayType.cast(ArrayMultidimensionalizer.multidimensionalize(_imag, _dimensions));
		}

		return array;
	}

	@Override
	boolean isSparse() {
		return false;
	}

	int getLinearIndex(int row, int column) {
		return ArrayUtils.checkedMultidimensionalIndicesToLinearIndex(_dimensions, row, column);
	}

	int getLinearIndex(int row, int column, int page) {
		return ArrayUtils.checkedMultidimensionalIndicesToLinearIndex(_dimensions, row, column, page);
	}

	int getLinearIndex(int row, int column, int[] pages) {
		return ArrayUtils.checkedMultidimensionalIndicesToLinearIndex(_dimensions, row, column, pages);
	}

	@Override
	public boolean equals(Object obj) {
		boolean equal = false;

		//Same object
		if (this == obj) {
			equal = true;
		}
		//Same class
		else if (obj != null && this.getClass().equals(obj.getClass())) {
			FullArray<?, ?> other = (FullArray<?, ?>) obj;

			//If the two instances are equal their hashcodes must be equal (but not the converse)
			if (this.hashCode() == other.hashCode()) {
				//Check equality of the elements of the arrays in expected increasing order of computational complexity

				//Same base components
				if (_baseComponentType.equals(other._baseComponentType)) {
					//Both real values, or both complex values
					if ((this.isReal() && other.isReal()) || (!this.isReal() && !other.isReal())) {
						//Same dimensions
						if (Arrays.equals(_dimensions, other._dimensions)) {
							//Finally, compare the inner arrays
							equal = ArrayUtils.equals(_real, other._real) &&
									ArrayUtils.equals(_imag, other._imag);
						}
					}
				}
			}
		}

		return equal;
	}

	@Override
	public int hashCode() {
		if (_hashCode == null) {
			int hashCode = 7;

			hashCode = 97 * hashCode + _baseComponentType.hashCode();
			hashCode = 97 * hashCode + ArrayUtils.hashCode(_real);
			hashCode = 97 * hashCode + ArrayUtils.hashCode(_imag);
			hashCode = 97 * hashCode + Arrays.hashCode(_dimensions);

			_hashCode = hashCode;
		}

		return _hashCode;
	}
}


<|start_filename|>src/matlabcontrol/MatlabBroadcaster.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.NoSuchObjectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Enables a session of MATLAB to be connected to by matlabcontrol running outside MATLAB.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabBroadcaster {
	/**
	 * A reference to the RMI registry which holds {@code MatlabSession}s.
	 */
	private static Registry _registry = null;

	/**
	 * Represents this session of MATLAB.
	 */
	private static final MatlabSessionImpl _session = new MatlabSessionImpl();

	/**
	 * The frequency (in milliseconds) with which to check if the connection to the registry still exists.
	 */
	private static final int BROADCAST_CHECK_PERIOD = 1000;

	/**
	 * The timer used to check if still connected to the registry.
	 */
	private static final Timer _broadcastTimer = new Timer("MLC Broadcast Maintainer");

	/**
	 * Private constructor so this class cannot be constructed.
	 */
	private MatlabBroadcaster() {}

	/**
	 * Returns the session object bound to the RMI registry by this broadcaster.
	 * 
	 * @return 
	 */
	static MatlabSessionImpl getSession() {
		return _session;
	}

	/**
	 * Makes this session of MATLAB visible to matlabcontrol. Once broadcasting, matlabcontrol running outside MATLAB
	 * will be able to connect to this session of MATLAB.
	 * 
	 * @throws MatlabConnectionException thrown if not running inside MATLAB or unable to broadcast
	 */
	synchronized static void broadcast(int broadcastPort) throws MatlabConnectionException {
		//If the registry hasn't been created
		if (_registry == null) {
			//Create or retrieve an RMI registry
			setupRegistry(broadcastPort);

			//Register this session so that it can be reconnected to
			bindSession();

			//If the registry becomes disconnected, either create a new one or locate a new one
			maintainRegistryConnection(broadcastPort);
		}
	}

	/**
	 * Attempts to create a registry, and if that cannot be done, then attempts to get an existing registry.
	 * 
	 * @throws MatlabConnectionException if a registry can neither be created nor retrieved
	 */
	private static void setupRegistry(int broadcastPort) throws MatlabConnectionException {
		try {
			_registry = LocalHostRMIHelper.createRegistry(broadcastPort);
		}
		//If we can't create one, try to retrieve an existing one
		catch (Exception e) {
			try {
				_registry = LocalHostRMIHelper.getRegistry(broadcastPort);
			} catch (Exception ex) {
				throw new MatlabConnectionException("Could not create or connect to the RMI registry", ex);
			}
		}
	}

	/**
	 * Binds the session object, an instance of {@link MatlabSession} to the registry with {@link #SESSION_ID}.
	 * 
	 * @throws MatlabConnectionException 
	 */
	private static void bindSession() throws MatlabConnectionException {
		//Unexport the object, it will throw an exception if it is not bound - so ignore that
		try {
			UnicastRemoteObject.unexportObject(_session, true);
		} catch (NoSuchObjectException e) {}

		try {
			_registry.bind(_session.getSessionID(), LocalHostRMIHelper.exportObject(_session));
		} catch (Exception e) {
			throw new MatlabConnectionException("Could not register this session of MATLAB", e);
		}
	}

	/**
	 * Checks with a timer that the registry still exists and that the session object is exported to it. If either
	 * stop being the case then an attempt is made to re-establish.
	 */
	private static void maintainRegistryConnection(final int broadcastPort) {
		//Configure the a timer to monitor the broadcast
		_broadcastTimer.schedule(new TimerTask() {
			@Override
			public void run() {
				//Check if the registry is connected
				try {
					//Will succeed if connected and the session object is still exported
					_registry.lookup(_session.getSessionID());
				}
				//Session object is no longer exported
				catch (NotBoundException e) {
					try {
						bindSession();
					}
					//Nothing more can be done if this fails
					catch (MatlabConnectionException ex) {}
				}
				//Registry is no longer connected
				catch (RemoteException e) {
					try {
						setupRegistry(broadcastPort);
						bindSession();
					}
					//Nothing more can be done if this fails
					catch (MatlabConnectionException ex) {}
				}
			}
		}, BROADCAST_CHECK_PERIOD, BROADCAST_CHECK_PERIOD);
	}
}


<|start_filename|>src/matlabcontrol/JMIValidator.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;

/**
 * Validates that the methods used by {@link JMIWrapper} are present in the current Java Virtual Machine, which should
 * always be MATLAB's JVM when this class is used. This is done because {@code jmi.jar} is entirely undocumented and
 * could change in any future release without notice. If that occurred it could result in a number of exceptions that
 * could be insufficiently informative to resolve the issue. This class throws detailed exceptions when an expected
 * method (or class the method belongs to) is not found.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class JMIValidator {
	private JMIValidator() {}

	/**
	 * Checks that all of the methods matlabcontrol uses are present. If they are all present then nothing will happen.
	 * If not, then an informative exception is thrown.
	 * 
	 * @throws MatlabConnectionException 
	 */
	static void validateJMIMethods() throws MatlabConnectionException {
		//Class: com.mathworks.jmi.Matlab
		Class<?> matlabClass = getAndCheckClass("com.mathworks.jmi.Matlab");

		//Method: public static Object mtFevalConsoleOutput(String, Object[], int) throws Exception
		checkMethod(matlabClass, Object.class, "mtFevalConsoleOutput",
				new Class<?>[]{String.class, Object[].class, int.class},
				new Class<?>[]{Exception.class});

		//Method: public static void whenMatlabIdle(Runnable)
		checkMethod(matlabClass, Void.TYPE, "whenMatlabIdle",
				new Class<?>[]{Runnable.class},
				new Class<?>[0]);

		//Class: com.mathworks.jmi.NativeMatlab
		Class<?> nativeMatlabClass = getAndCheckClass("com.mathworks.jmi.NativeMatlab");

		//Method: public static boolean nativeIsMatlabThread()
		checkMethod(nativeMatlabClass, boolean.class, "nativeIsMatlabThread",
				new Class<?>[0],
				new Class<?>[0]);
	}

	private static Class<?> getAndCheckClass(String className) throws MatlabConnectionException {
		try {
			return Class.forName(className, false, JMIValidator.class.getClassLoader());
		} catch (ClassNotFoundException e) {
			throw new MatlabConnectionException("This version of MATLAB is missing a class required by matlabcontrol\n" +
					"Required: " + className, e);
		}
		//Should not occur: MATLAB by default has no SecurityManager installed and PermissiveSecurityManager permits this
		catch (SecurityException e) {
			throw new MatlabConnectionException("Unable to verify if MATLAB has the method required by matlabcontrol", e);
		}
	}

	/**
	 * Checks that there exists a method named {@code methodName} for class {@code clazz} that is {@code public static},
	 * return {@code requiredReturn}, has parameters {@code reqiredParameters} (in the specified order), and throws
	 * {@code requiredExceptions}. Exceptions that extend {@link RuntimeException} are ignored.
	 * 
	 * 
	 * @param clazz
	 * @param requiredReturn
	 * @param methodName
	 * @param requiredParameters
	 * @param requiredExceptions
	 * @throws MatlabConnectionException 
	 */
	private static void checkMethod(Class<?> clazz, Class<?> requiredReturn, String methodName,
			Class<?>[] requiredParameters, Class<?>[] requiredExceptions) throws MatlabConnectionException {
		try {
			Method method = clazz.getDeclaredMethod(methodName, requiredParameters);
			int actualModifiers = method.getModifiers();
			Class<?> actualReturn = method.getReturnType();
			Class<?>[] actualExceptions = method.getExceptionTypes();

			//Determine if the exceptions are equivalent
			boolean exceptionsEqual = doExceptionsMatch(requiredExceptions, actualExceptions);

			if (!Modifier.isPublic(actualModifiers) || !Modifier.isStatic(actualModifiers) ||
					!actualReturn.equals(requiredReturn) || !exceptionsEqual) {
				String required = buildMethodDescription(clazz, requiredReturn, methodName, requiredParameters, requiredExceptions);

				throw new MatlabConnectionException("This version of MATLAB is missing a method required by matlabcontrol\n" +
						"Required: " + required + "\n" +
						"Found:    " + method.toString());
			}
		} catch (NoSuchMethodException e) {
			String required = buildMethodDescription(clazz, requiredReturn, methodName, requiredParameters, requiredExceptions);

			throw new MatlabConnectionException("This version of MATLAB is missing a method required by matlabcontrol\n" +
					"Required: " + required);
		}
	}

	/**
	 * Determine if the {@link Exception} classes are equivalent, ignoring {@link RuntimeException}s.
	 * 
	 * @param requiredExceptions
	 * @param actualExceptions
	 * @return 
	 */
	private static boolean doExceptionsMatch(Class<?>[] requiredExceptions, Class<?>[] actualExceptions) {
		HashSet<Class<?>> requiredSet = new HashSet<Class<?>>();
		for (Class<?> excClass : requiredExceptions) {
			if (!RuntimeException.class.isAssignableFrom(excClass)) {
				requiredSet.add(excClass);
			}
		}

		HashSet<Class<?>> actualSet = new HashSet<Class<?>>();
		for (Class<?> excClass : actualExceptions) {
			if (!RuntimeException.class.isAssignableFrom(excClass)) {
				actualSet.add(excClass);
			}
		}

		return requiredSet.equals(actualSet);

	}

	/**
	 * Builds a String representation of the form:
	 * {@code
	 * public static [requiredReturn] [methodName]([requiredParameters]) throws [requiredExceptions]
	 * }
	 * If no exceptions are thrown then the "throws" part will not occur.
	 * 
	 * @param clazz
	 * @param requiredReturn
	 * @param methodName
	 * @param requiredParameters
	 * @param requiredExceptions
	 * @return 
	 */
	private static String buildMethodDescription(Class<?> clazz, Class<?> requiredReturn, String methodName,
			Class<?>[] requiredParameters, Class<?>[] requiredExceptions) {
		StringBuilder paramString = new StringBuilder();
		for (int i = 0; i < requiredParameters.length; i++) {
			paramString.append(requiredParameters[i].getCanonicalName());

			if (i < requiredParameters.length - 1) {
				paramString.append(",");
			}
		}

		StringBuilder throwsString = new StringBuilder();
		if (requiredExceptions.length > 0) {
			throwsString.append(" throws ");
			for (int i = 0; i < requiredExceptions.length; i++) {
				throwsString.append(requiredExceptions[i].getCanonicalName());

				if (i < requiredExceptions.length - 1) {
					throwsString.append(",");
				}
			}
		}

		String desc = "public static " + requiredReturn.getCanonicalName() + " " +
				clazz.getCanonicalName() + "." + methodName + "(" + paramString + ")" + throwsString;

		return desc;
	}
}


<|start_filename|>src/matlabcontrol/JMIWrapperRemote.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * Methods that can be called to control MATLAB except for {@link #checkConnection()}.
 * <br><br>
 * All of these methods throw RemoteException. RemoteException will be thrown if something occurs to disrupt the
 * communication between this JVM and the one MATLAB is running in. For instance, closing MATLAB will terminate its
 * JVM and then all method calls on this proxy will throw exceptions.
 * <br><br>
 * For descriptions of what these methods do see the corresponding methods in {@link MatlabProxy}.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
interface JMIWrapperRemote extends Remote {
	public void exit() throws RemoteException;

	public void setVariable(String variableName, Object value) throws RemoteException, MatlabInvocationException;

	public Object getVariable(String variableName) throws RemoteException, MatlabInvocationException;

	public void eval(String command) throws RemoteException, MatlabInvocationException;

	public Object[] returningEval(String command, int nargout) throws RemoteException, MatlabInvocationException;

	public void feval(String command, Object... args) throws RemoteException, MatlabInvocationException;

	public Object[] returningFeval(String command, int nargout, Object... args) throws RemoteException, MatlabInvocationException;

	public <U> U invokeAndWait(MatlabProxy.MatlabThreadCallable<U> callable) throws RemoteException, MatlabInvocationException;

	/**
	 * This method does nothing. It is used internally to check if a connection is still active via calling this method
	 * and seeing if it throws a {@code RemoteException} (if it does, the connection is no longer active).
	 * 
	 * @throws RemoteException
	 */
	public void checkConnection() throws RemoteException;
}


<|start_filename|>src/matlabcontrol/extensions/CallbackMatlabProxy.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.extensions;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxy.MatlabThreadCallable;

/**
 * @deprecated This class was provided as a workaround when {@link MatlabProxy} could not operate on the Event Dispatch
 * Thread (EDT) used by AWT and Swing; {@code MatlabProxy} no longer has this limitation.
 * 
 * Wraps around a {@link MatlabProxy} making the method calls which interact with MATLAB operate with callbacks instead
 * of return values. For each method in {@code MatlabProxy} that interacts with MATLAB, the same method exists but has
 * one additional parameter that is either {@link MatlabCallback} or {@link MatlabDataCallback}. Method invocations do
 * not throw {@link MatlabInvocationException}s, but if the proxy throws a {@code MatlabInvocationException} it will be
 * provided to the callback.
 * <br><br>
 * All interactions with the proxy will be done in a single threaded manner. The underlying proxy methods will be
 * completed in the order their corresponding methods in this class were called. Because method invocations on the
 * proxy occur on a separate thread from the one calling the methods in this class, it can be used from within MATLAB on
 * the Event Dispatch Thread (EDT).
 * <br><br>
 * This class is unconditionally thread-safe. There are no guarantees about the relative ordering of method completion
 * when methods are invoked both on an instance of this class and on the proxy provided to it.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class CallbackMatlabProxy {
	/**
	 * Executor that manages the single daemon thread used to invoke methods on the proxy. 
	 */
	private final ExecutorService _executor = Executors.newFixedThreadPool(1, new DaemonThreadFactory());

	private final MatlabProxy _proxy;

	/**
	 * Constructs an instance of this class, delegating all method invocations to the {@code proxy}.
	 * 
	 * @param proxy 
	 */
	public CallbackMatlabProxy(MatlabProxy proxy) {
		_proxy = proxy;
	}

	/**
	 * Returns a brief description. The exact details of this representation are unspecified and are subject to change.
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "[" + this.getClass().getName() + " proxy=" + _proxy + "]";
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 */
	public void isConnected(final MatlabDataCallback<Boolean> callback) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				boolean connected = _proxy.isConnected();
				callback.invocationSucceeded(connected);
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 */
	public void disconnect(final MatlabDataCallback<Boolean> callback) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				boolean succeeded = _proxy.disconnect();
				callback.invocationSucceeded(succeeded);
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 */
	public void exit(final MatlabCallback callback) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					_proxy.exit();
					callback.invocationSucceeded();
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param command
	 */
	public void eval(final MatlabCallback callback, final String command) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					_proxy.eval(command);
					callback.invocationSucceeded();
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param command
	 * @param nargout
	 */
	public void returningEval(final MatlabDataCallback<Object[]> callback, final String command, final int nargout) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Object[] data = _proxy.returningEval(command, nargout);
					callback.invocationSucceeded(data);
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param functionName
	 * @param args
	 */
	public void feval(final MatlabCallback callback, final String functionName, final Object... args) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					_proxy.feval(functionName, args);
					callback.invocationSucceeded();
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param functionName
	 * @param nargout
	 * @param args
	 */
	public void returningFeval(final MatlabDataCallback<Object[]> callback, final String functionName,
			final int nargout, final Object... args) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Object[] data = _proxy.returningFeval(functionName, nargout, args);
					callback.invocationSucceeded(data);
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param variableName
	 * @param value
	 */
	public void setVariable(final MatlabCallback callback, final String variableName, final Object value) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					_proxy.setVariable(variableName, value);
					callback.invocationSucceeded();
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the proxy's corresponding method has completed.
	 * 
	 * @param callback 
	 * @param variableName
	 */
	public void getVariable(final MatlabDataCallback<Object> callback, final String variableName) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Object data = _proxy.getVariable(variableName);
					callback.invocationSucceeded(data);
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * Delegates to the proxy, calling the {@code callback} when the method has been executed.
	 * <br><br>
	 * The name of this method has been retained for consistency with {@code MatlabProxy}, but note that while the
	 * code in the {@code callable} will be invoked on the MATLAB thread and it will wait until completion so as to
	 * return a result, this method - like all others in this class, will not wait for completion. Instead, the result
	 * will be provided to the {@code callback}.
	 * 
	 * @param callable
	 * @param callback 
	 */
	public <U> void invokeAndWait(final MatlabThreadCallable<U> callable, final MatlabDataCallback<U> callback) {
		_executor.submit(new Runnable() {
			@Override
			public void run() {
				try {
					U data = _proxy.invokeAndWait(callable);
					callback.invocationSucceeded(data);
				} catch (MatlabInvocationException e) {
					callback.invocationFailed(e);
				}
			}
		});
	}

	/**
	 * A callback that supplies the results of the invocation or the raised exception.
	 * 
	 * @param <V> 
	 */
	public static interface MatlabDataCallback<V> {
		/**
		 * Called when the method successfully completed.
		 * 
		 * @param data the data returned from MATLAB
		 */
		public void invocationSucceeded(V data);

		/**
		 * Called when the method failed.
		 * 
		 * @param e the exception thrown 
		 */
		public void invocationFailed(MatlabInvocationException e);
	}

	/**
	 * A callback that indicates either the invocation succeeding or an exception being raised.
	 */
	public static interface MatlabCallback {
		/**
		 * Called when the method successfully completed.
		 */
		public void invocationSucceeded();

		/**
		 * Called when the method failed.
		 * 
		 * @param e the exception thrown 
		 */
		public void invocationFailed(MatlabInvocationException e);
	}

	/**
	 * Creates daemon threads that will allow the JVM to terminate.
	 */
	private static class DaemonThreadFactory implements ThreadFactory {
		private final ThreadFactory _delegateFactory = Executors.defaultThreadFactory();

		@Override
		public Thread newThread(Runnable r) {
			Thread thread = _delegateFactory.newThread(r);
			thread.setName("MatlabCallbackInteractor Thread");
			thread.setDaemon(true);

			return thread;
		}
	}
}


<|start_filename|>src/matlabcontrol/demo/RemoteMain.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.awt.EventQueue;

import javax.swing.WindowConstants;

/**
 * Launches the demo when running outside MATLAB.
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class RemoteMain {
	public static void main(String[] args) {
		final String matlabLocation = (args.length == 1 ? args[0] : null);
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				DemoFrame frame = new DemoFrame("matlabcontrol demo - Running Outside MATLAB", matlabLocation);
				frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
				frame.setVisible(true);
			}
		});
	}
}


<|start_filename|>src/matlabcontrol/demo/ReturnFormatter.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;

/**
 * Formats returned {@code Object}s and {@code Exception}s from MATLAB.
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class ReturnFormatter {
	private ReturnFormatter() {}

	/**
	 * Format the exception into a string that can be displayed.
	 * 
	 * @param exc the exception
	 * @return the exception as a string
	 */
	public static String formatException(Exception exc) {
		StringWriter stringWriter = new StringWriter();
		PrintWriter printWriter = new PrintWriter(stringWriter);
		exc.printStackTrace(printWriter);
		try {
			stringWriter.close();
		} catch (IOException ex) {}

		return stringWriter.toString();
	}

	/**
	 * Takes in the result from MATLAB and turns it into an easily readable format.
	 * 
	 * @param result
	 * @return description
	 */
	public static String formatResult(Object result) {
		return formatResult(result, 0);
	}

	/**
	 * Takes in the result from MATLAB and turns it into an easily readable format.
	 * 
	 * @param result
	 * @param level, pass in 0 to initialize, used recursively
	 * @return description
	 */
	private static String formatResult(Object result, int level) {
		//Message builder
		StringBuilder builder = new StringBuilder();

		//Tab offset for levels
		String tab = "";
		for (int i = 0; i < level + 1; i++) {
			tab += "  ";
		}

		//If the result is null
		if (result == null) {
			builder.append("null encountered\n");
		}
		//If the result is an array
		else if (result.getClass().isArray()) {
			Class<?> componentClass = result.getClass().getComponentType();

			//Primitive array
			if (componentClass.isPrimitive()) {
				String componentName = componentClass.toString();
				int length = Array.getLength(result);

				builder.append(componentName);
				builder.append(" array, length = ");
				builder.append(length);
				builder.append("\n");

				for (int i = 0; i < length; i++) {
					builder.append(tab);
					builder.append("index ");
					builder.append(i);
					builder.append(", ");
					builder.append(componentName);
					builder.append(": ");
					builder.append(Array.get(result, i));
					builder.append("\n");
				}
			}
			//Object array
			else {
				Object[] array = (Object[]) result;

				builder.append(array.getClass().getComponentType().getName());
				builder.append(" array, length = ");
				builder.append(array.length);
				builder.append("\n");

				for (int i = 0; i < array.length; i++) {
					builder.append(tab);
					builder.append("index ");
					builder.append(i);
					builder.append(", ");
					builder.append(formatResult(array[i], level + 1));
				}
			}
		}
		//If an Object and not an array
		else {
			builder.append(result.getClass().getCanonicalName());
			builder.append(": ");
			builder.append(result);
			builder.append("\n");
		}

		return builder.toString();
	}
}


<|start_filename|>src/matlabcontrol/RequestReceiver.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * Represents a receiver for a request to create a proxy. The receiver must be bound to an RMI registry, it will be
 * bound with the RMI identifier {@link #getReceiverID()}. Necessary to have this interface for RMI.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
interface RequestReceiver extends Remote {
	/**
	 * Receives an incoming wrapper around the JMI functionality inside of MATLAB.
	 * <br><br>
	 * This method is to be called by {@link MatlabConnector} running inside of MATLAB's JVM.
	 * 
	 * @param jmiWrapper
	 * @param existingSession if the session sending the jmiWrapper was running prior to the request to create the proxy
	 * @throws RemoteException 
	 */
	public void receiveJMIWrapper(JMIWrapperRemote jmiWrapper, boolean existingSession) throws RemoteException;

	/**
	 * The identifier of the receiver.
	 * 
	 * @return
	 * @throws RemoteException 
	 */
	public String getReceiverID() throws RemoteException;

	/**
	 * The classpath of the VM the receiver was created in encoded as an RMI codebase.
	 * 
	 * @return
	 * @throws RemoteException 
	 */
	public String getClassPathAsRMICodebase() throws RemoteException;

	/**
	 * The classpath of the VM the receiver was created in encoded as canonical paths.
	 * 
	 * @return
	 * @throws RemoteException 
	 */
	public String[] getClassPathAsCanonicalPaths() throws RemoteException;
}


<|start_filename|>src/matlabcontrol/link/MatlabInt8.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * MATLAB {@code int8} with real and imaginary components.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabInt8 extends MatlabNumber<Byte> {
	private static final Byte DEFAULT = 0;

	public MatlabInt8(byte real, byte imag) {
		super(DEFAULT, real, imag);
	}

	/**
	 * Returns the real value.
	 * 
	 * @return 
	 */
	public byte toReal() {
		return _real;
	}

	/**
	 * Returns the imaginary value.
	 * 
	 * @return 
	 */
	public byte toImaginary() {
		return _imag;
	}
}


<|start_filename|>src/matlabcontrol/ThrowableWrapper.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

/**
 * A wrapper around any {@link Throwable} so that it  can be sent over RMI without needing the class to be defined in
 * the receiving JVM. The stack trace will print as if it were the original throwable.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class ThrowableWrapper extends Throwable {
	private static final long serialVersionUID = 0xC500L;

	/**
	 * The {@code String} representation of the {@code MatlabException} so that this exception can pretend to be a
	 * {@code MatlabException}.
	 */
	private final String _toString;

	/**
	 * Creates a wrapper around {@code innerThrowable} so that when the stack trace is printed it is the same to the
	 * developer, but can be sent over RMI without the throwable being defined in the other JVM.
	 * 
	 * @param innerThrowable
	 */
	ThrowableWrapper(Throwable innerThrowable) {
		super(msgFromToString(innerThrowable));
		//Store innerThrowable's toString() value
		_toString = innerThrowable.toString();

		//Set this stack trace to that of the innerThrowable
		this.setStackTrace(innerThrowable.getStackTrace());

		//Store the cause, wrapping it
		if (innerThrowable.getCause() != null) {
			this.initCause(new ThrowableWrapper(innerThrowable.getCause()));
		}
	}

	/**
	 * The innerThrowable seems to not implement getMessage() properly.
	 * 
	 * So we extract the message from the exception's toString() method.
	 */
	static String msgFromToString(Throwable e) {
		String msg = e.toString();
		int idx = msg.indexOf(':');
		if (idx >= 0 && idx < msg.length() - 1) {
			return msg.substring(idx + 1);
		} else {
			return msg;
		}
	}

	@Override
	public String toString() {
		return _toString;
	}
}


<|start_filename|>src/matlabcontrol/demo/DemoFrame.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.text.NumberFormat;
import java.util.concurrent.atomic.AtomicReference;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import matlabcontrol.MatlabConnectionException;
import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxyFactory;
import matlabcontrol.MatlabProxyFactoryOptions;
import matlabcontrol.PermissiveSecurityManager;

/**
 * A GUI example to demonstrate the main functionality of controlling MATLAB with matlabcontrol. The code in this
 * class (and the rest of the package) is not intended to serve as an example for how to use matlabcontrol, instead
 * the application exists to interactively demonstrate the API's capabilities.
 * <br><br>
 * The icon is part of the Um collection created by <a href="mailto:<EMAIL>">mattahan (<NAME>)</a>. It is
 * licensed under the <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">CC Attribution-Noncommercial-Share
 * Alike 3.0 License</a>.
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@SuppressWarnings("serial")
public class DemoFrame extends JFrame {
	//Status messages
	private static final String STATUS_DISCONNECTED = "Connection Status: Disconnected",
			STATUS_CONNECTING = "Connection Status: Connecting",
			STATUS_CONNECTED_EXISTING = "Connection Status: Connected (Existing)",
			STATUS_CONNECTED_LAUNCHED = "Connection Status: Connected (Launched)";

	//Return messages
	private static final String RETURNED_DEFAULT = "Returned Object / Java Exception",
			RETURNED_OBJECT = "Returned Object",
			RETURNED_EXCEPTION = "Java Exception";

	//Panel/Pane sizes
	private static final int PANEL_WIDTH = 660;
	private static final Dimension CONNECTION_PANEL_SIZE = new Dimension(PANEL_WIDTH, 70),
			RETURN_PANEL_SIZE = new Dimension(PANEL_WIDTH, 250),
			METHOD_PANEL_SIZE = new Dimension(PANEL_WIDTH, 110 + 28 * ArrayPanel.NUM_ENTRIES),
			DESCRIPTION_PANE_SIZE = new Dimension(PANEL_WIDTH, 200),
			COMMAND_PANEL_SIZE = new Dimension(PANEL_WIDTH, METHOD_PANEL_SIZE.height + DESCRIPTION_PANE_SIZE.height),
			MAIN_PANEL_SIZE = new Dimension(PANEL_WIDTH, CONNECTION_PANEL_SIZE.height + COMMAND_PANEL_SIZE.height + RETURN_PANEL_SIZE.height);
	//Factory to create proxy
	private final MatlabProxyFactory _factory;

	//Proxy to communicate with MATLAB
	private final AtomicReference<MatlabProxy> _proxyHolder = new AtomicReference<MatlabProxy>();

	//UI components
	private JButton _invokeButton;
	private JScrollPane _returnPane;
	private JTextArea _returnArea;

	public static BufferedImage getIcon() {
		try {
			return ImageIO.read(DemoFrame.class.getResource("/matlabcontrol/demo/logo_128.png"));
		} catch (Exception e) {
			e.printStackTrace();
			return new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
		}
	}

	/**
	 * Create the main GUI.
	 */
	public DemoFrame(String title, String matlabLocation) {
		super(title);

		System.setSecurityManager(new PermissiveSecurityManager());
		setIconImage(getIcon());

		//Panel that contains the over panels
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BorderLayout());
		mainPanel.setBackground(Color.WHITE);
		mainPanel.setPreferredSize(MAIN_PANEL_SIZE);
		mainPanel.setSize(MAIN_PANEL_SIZE);
		this.add(mainPanel);

		//Connection panel, button to connect, progress bar
		final JPanel connectionPanel = new JPanel();
		connectionPanel.setBackground(mainPanel.getBackground());
		connectionPanel.setBorder(BorderFactory.createTitledBorder(STATUS_DISCONNECTED));
		connectionPanel.setPreferredSize(CONNECTION_PANEL_SIZE);
		connectionPanel.setSize(CONNECTION_PANEL_SIZE);
		final JButton connectionButton = new JButton("Connect");
		connectionPanel.add(connectionButton);
		final JProgressBar connectionBar = new JProgressBar();
		connectionPanel.add(connectionBar);

		//To display what has been returned from MATLAB
		_returnArea = new JTextArea();
		_returnArea.setEditable(false);

		//Put the returnArea in pane, add it
		_returnPane = new JScrollPane(_returnArea);
		_returnPane.setBackground(Color.WHITE);
		_returnPane.setPreferredSize(RETURN_PANEL_SIZE);
		_returnPane.setBorder(BorderFactory.createTitledBorder(RETURNED_DEFAULT));

		//Command Panel
		JPanel commandPanel = this.createCommandPanel();

		//Structure the panels so that on resize the layout updates appropriately
		JPanel combinedPanel = new JPanel(new BorderLayout());
		combinedPanel.add(connectionPanel, BorderLayout.NORTH);
		combinedPanel.add(commandPanel, BorderLayout.SOUTH);
		mainPanel.add(combinedPanel, BorderLayout.NORTH);
		mainPanel.add(_returnPane, BorderLayout.CENTER);

		this.pack();

		//Create proxy factory
		MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
				.setUsePreviouslyControlledSession(true)
				.setMatlabLocation(matlabLocation)
				.build();
		_factory = new MatlabProxyFactory(options);

		//Connect to MATLAB when the Connect button is pressed
		connectionButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					//Request a proxy
					_factory.requestProxy(new MatlabProxyFactory.RequestCallback() {
						@Override
						public void proxyCreated(final MatlabProxy proxy) {
							_proxyHolder.set(proxy);

							proxy.addDisconnectionListener(new MatlabProxy.DisconnectionListener() {
								@Override
								public void proxyDisconnected(MatlabProxy proxy) {
									_proxyHolder.set(null);

									//Visual update
									EventQueue.invokeLater(new Runnable() {
										@Override
										public void run() {
											connectionPanel.setBorder(BorderFactory.createTitledBorder(STATUS_DISCONNECTED));
											_returnPane.setBorder(BorderFactory.createTitledBorder(RETURNED_DEFAULT));
											_returnArea.setText("");
											connectionBar.setValue(0);
											connectionButton.setEnabled(true);
											_invokeButton.setEnabled(false);
										}
									});
								}
							});

							//Visual update
							EventQueue.invokeLater(new Runnable() {
								@Override
								public void run() {
									String status;
									if (proxy.isExistingSession()) {
										status = STATUS_CONNECTED_EXISTING;
									} else {
										status = STATUS_CONNECTED_LAUNCHED;
									}
									connectionPanel.setBorder(BorderFactory.createTitledBorder(status));

									connectionBar.setValue(100);
									connectionBar.setIndeterminate(false);
									_invokeButton.setEnabled(true);
								}
							});
						}
					});

					//Update GUI
					connectionPanel.setBorder(BorderFactory.createTitledBorder(STATUS_CONNECTING));
					connectionBar.setIndeterminate(true);
					connectionButton.setEnabled(false);
				} catch (MatlabConnectionException exc) {
					_returnPane.setBorder(BorderFactory.createTitledBorder(RETURNED_EXCEPTION));
					_returnArea.setText(ReturnFormatter.formatException(exc));
					_returnArea.setCaretPosition(0);
				}
			}
		});

		//Window events
		this.addWindowListener(new WindowAdapter() {
			/**
			 * On window appearance set the minimum size to the same width and 80% of the height.
			 */
			@Override
			public void windowOpened(WindowEvent e) {
				Dimension size = DemoFrame.this.getSize();
				size.height *= .8;
				DemoFrame.this.setMinimumSize(size);
			}
		});
	}

	/**
	 * Create the command panel.
	 * 
	 * @param returnArea
	 * @return
	 */
	private JPanel createCommandPanel() {
		//Panel that contains the methods, input, and description
		JPanel commandPanel = new JPanel(new BorderLayout());
		commandPanel.setBackground(Color.WHITE);
		commandPanel.setPreferredSize(COMMAND_PANEL_SIZE);
		commandPanel.setSize(COMMAND_PANEL_SIZE);

		//Method
		JPanel methodPanel = new JPanel(new BorderLayout());
		methodPanel.setBorder(BorderFactory.createTitledBorder("Method"));
		methodPanel.setBackground(Color.WHITE);
		methodPanel.setPreferredSize(METHOD_PANEL_SIZE);
		methodPanel.setSize(METHOD_PANEL_SIZE);
		commandPanel.add(methodPanel, BorderLayout.NORTH);

		//Upper part - drop down and button
		JPanel methodUpperPanel = new JPanel();
		methodUpperPanel.setBackground(Color.WHITE);
		methodPanel.add(methodUpperPanel, BorderLayout.NORTH);
		//Lower part - input fields
		JPanel methodLowerPanel = new JPanel();
		methodLowerPanel.setBackground(Color.WHITE);
		methodPanel.add(methodLowerPanel, BorderLayout.SOUTH);

		//Method choice
		final JComboBox methodBox = new JComboBox(ProxyMethodDescriptor.values());
		methodUpperPanel.add(methodBox);

		//Invoke button
		_invokeButton = new JButton("Invoke");
		_invokeButton.setEnabled(false);
		methodUpperPanel.add(_invokeButton);

		//Input
		final JTextField field = new JTextField();
		field.setBackground(methodPanel.getBackground());
		field.setColumns(16);
		methodLowerPanel.add(field);

		//Return count
		final JFormattedTextField nargoutField = new JFormattedTextField(NumberFormat.INTEGER_FIELD);
		nargoutField.setBackground(methodPanel.getBackground());
		nargoutField.setColumns(8);
		nargoutField.setBorder(BorderFactory.createTitledBorder("nargout"));
		methodLowerPanel.add(nargoutField);

		//Array entries
		final ArrayPanel arrayPanel = new ArrayPanel();
		methodLowerPanel.add(arrayPanel);

		//Method description
		final JEditorPane descriptionArea = new JEditorPane("text/html", "");
		descriptionArea.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
		JScrollPane descriptionPane = new JScrollPane(descriptionArea);
		descriptionPane.setBackground(Color.WHITE);
		descriptionArea.setFont(new Font("SansSerif", Font.PLAIN, 13));
		descriptionPane.setBorder(BorderFactory.createTitledBorder("Method description"));
		descriptionPane.setPreferredSize(DESCRIPTION_PANE_SIZE);
		descriptionArea.setEditable(false);
		commandPanel.add(descriptionPane, BorderLayout.SOUTH);

		//Listen for method choices
		methodBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				//Get selected method
				ProxyMethodDescriptor method = (ProxyMethodDescriptor) methodBox.getSelectedItem();

				//Update box titles
				field.setBorder(BorderFactory.createTitledBorder(method.stringInputName));

				//Disable/enable return count and update text appropriately
				if (method.returnCountEnabled) {
					nargoutField.setText("1");
					nargoutField.setEnabled(true);
				} else {
					nargoutField.setText("N/A");
					nargoutField.setEnabled(false);
				}

				//Disable/enable array input appropriately
				arrayPanel.setBorder(BorderFactory.createTitledBorder(method.argsInputName));
				arrayPanel.enableInputFields(method.argsInputNumberEnabled);

				//Update description text
				descriptionArea.setText(method.message);
				//Scroll to the top of the description text
				descriptionArea.setCaretPosition(0);

				//Select text in field and switch focus
				field.selectAll();
				field.grabFocus();
			}
		});
		//Select first index to have action take effect
		methodBox.setSelectedIndex(0);

		//Invoke button action
		_invokeButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				ProxyMethodDescriptor descriptor = (ProxyMethodDescriptor) methodBox.getSelectedItem();

				//eval(String command)
				if (descriptor == ProxyMethodDescriptor.EVAL) {
					try {
						_proxyHolder.get().eval(field.getText());
						displayReturn();
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}
				}
				//returningEval(String command, int nargout)
				else if (descriptor == ProxyMethodDescriptor.RETURNING_EVAL) {
					int nargout = 0;
					try {
						nargout = Integer.parseInt(nargoutField.getText());
					} catch (Exception ex) {}

					try {
						displayResult(_proxyHolder.get().returningEval(field.getText(), nargout));
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}
				}
				//feval(String functionName, Object... args)
				else if (descriptor == ProxyMethodDescriptor.FEVAL) {
					try {
						_proxyHolder.get().feval(field.getText(), arrayPanel.getArray());
						displayReturn();
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}
				}
				//returningFeval(String functionName, int nargout, Object... args)
				else if (descriptor == ProxyMethodDescriptor.RETURNING_FEVAL) {
					int nargout = 0;
					try {
						nargout = Integer.parseInt(nargoutField.getText());
					} catch (Exception ex) {}

					try {
						displayResult(_proxyHolder.get().returningFeval(field.getText(), nargout, arrayPanel.getArray()));
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}

				}
				//setVariable(String variableName, Object value)
				else if (descriptor == ProxyMethodDescriptor.SET_VARIABLE) {
					try {
						_proxyHolder.get().setVariable(field.getText(), arrayPanel.getFirstEntry());
						displayReturn();
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}
				}
				//getVariable(String variableName)
				else if (descriptor == ProxyMethodDescriptor.GET_VARIABLE) {
					try {
						displayResult(_proxyHolder.get().getVariable(field.getText()));
					} catch (MatlabInvocationException ex) {
						displayException(ex);
					}
				}
			}
		});

		return commandPanel;
	}

	private void displayReturn() {
		_returnArea.setText("");
	}

	private void displayResult(Object result) {
		_returnPane.setBorder(BorderFactory.createTitledBorder(RETURNED_OBJECT));
		_returnArea.setForeground(Color.BLACK);
		_returnArea.setText(ReturnFormatter.formatResult(result));
		_returnArea.setCaretPosition(0);
	}

	private void displayException(Exception exc) {
		_returnPane.setBorder(BorderFactory.createTitledBorder(RETURNED_EXCEPTION));
		_returnArea.setForeground(Color.RED);
		_returnArea.setText(ReturnFormatter.formatException(exc));
		_returnArea.setCaretPosition(0);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabLogicalSparseMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabLogicalSparseMatrix extends MatlabLogicalMatrix<boolean[][]> {
	private final SparseArray<boolean[]> _array;

	MatlabLogicalSparseMatrix(int[] linearIndices, int[] rowIndices, int[] colIndices, boolean[] values,
			int numRows, int numCols) {
		_array = new SparseArray<boolean[]>(boolean[].class, linearIndices, rowIndices, colIndices, values, null,
				numRows, numCols);
	}

	MatlabLogicalSparseMatrix(int[] rowIndices, int[] colIndices, boolean[] values, int numRows, int numCols) {
		_array = new SparseArray<boolean[]>(boolean[].class, rowIndices, colIndices, values, null, numRows, numCols);
	}

	@Override
	BaseArray<boolean[], boolean[][]> getBaseArray() {
		return _array;
	}

	private boolean getElementAtSparseIndex(int sparseIndex) {
		boolean val = false;
		if (sparseIndex >= 0) {
			val = _array._realValues[sparseIndex];
		}

		return val;
	}

	@Override
	public boolean getElementAtLinearIndex(int linearIndex) {
		return getElementAtSparseIndex(_array.getSparseIndexForLinearIndex(linearIndex));
	}

	@Override
	public boolean getElementAtIndices(int row, int column) {
		return getElementAtSparseIndex(_array.getSparseIndexForIndices(row, column));
	}

	@Override
	public boolean getElementAtIndices(int row, int column, int page) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using 3 indices");
	}

	@Override
	public boolean getElementAtIndices(int row, int column, int[] pages) {
		throw new IllegalArgumentException("Array has 2 dimensions, it cannot be indexed into using " +
				(2 + pages.length) + " indices");
	}
}


<|start_filename|>src/matlabcontrol/link/LinkedOperations.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.MatlabProxy;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class LinkedOperations implements MatlabOperations {
	private final MatlabProxy _delegateProxy;
	private final MatlabOperations _delegateOperations;

	public LinkedOperations(MatlabProxy proxy) {
		_delegateProxy = proxy;
		_delegateOperations = Linker.getLinkedMatlabOperations(proxy);
	}

	@Override
	public void eval(String command) throws MatlabInvocationException {
		_delegateOperations.eval(command);
	}

	@Override
	public Object[] returningEval(String command, int nargout) throws MatlabInvocationException {
		return _delegateOperations.returningEval(command, nargout);
	}

	@Override
	public void feval(String functionName, Object... args) throws MatlabInvocationException {
		_delegateOperations.feval(functionName, args);
	}

	@Override
	public Object[] returningFeval(String functionName, int nargout, Object... args) throws MatlabInvocationException {
		return _delegateOperations.returningFeval(functionName, nargout, args);
	}

	@Override
	public void setVariable(String variableName, Object value) throws MatlabInvocationException {
		_delegateOperations.setVariable(variableName, value);
	}

	@Override
	public Object getVariable(String variableName) throws MatlabInvocationException {
		return _delegateOperations.getVariable(variableName);
	}

	/**
	 * The proxy used to communicate with MATLAB.
	 * 
	 * @return proxy
	 */
	public MatlabProxy getDelegateProxy() {
		return _delegateProxy;
	}
}


<|start_filename|>src/matlabcontrol/demo/ArrayPanel.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * The panel that contains the options to select elements of the array.
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@SuppressWarnings("serial")
class ArrayPanel extends JPanel {
	//Input options: String or Double
	private static final int DOUBLE_INDEX = 0, STRING_INDEX = 1;

	private static final String[] OPTIONS = new String[2];

	static {
		OPTIONS[DOUBLE_INDEX] = "Double";
		OPTIONS[STRING_INDEX] = "String";
	}

	/**
	 * Number of fields and drop down lists.
	 */
	public static final int NUM_ENTRIES = 3;

	/**
	 * Drop down lists to choose between object types.
	 */
	private final JComboBox[] _optionBoxes;

	/**
	 * Fields for inputting values.
	 */
	private final JTextField[] _entryFields;

	public ArrayPanel() {
		super(new GridLayout(NUM_ENTRIES, 2));
		this.setBackground(Color.WHITE);

		//Drop down lists and input fields
		_optionBoxes = new JComboBox[NUM_ENTRIES];
		_entryFields = new JTextField[NUM_ENTRIES];

		for (int i = 0; i < NUM_ENTRIES; i++) {
			_optionBoxes[i] = new JComboBox(OPTIONS);
			_entryFields[i] = new JTextField(8);
			this.add(_optionBoxes[i]);
			this.add(_entryFields[i]);
		}
	}

	/**
	 * Take the elements of the fields and put them into an array.
	 * 
	 * @return
	 */
	public Object[] getArray() {
		ArrayList<Object> entries = new ArrayList<Object>();
		for (int i = 0; i < NUM_ENTRIES; i++) {
			if (!_entryFields[i].getText().isEmpty()) {
				if (_optionBoxes[i].getSelectedIndex() == DOUBLE_INDEX) {
					try {
						entries.add(Double.parseDouble(_entryFields[i].getText()));
					} catch (Exception e) {
						entries.add(0);
					}
				}
				if (_optionBoxes[i].getSelectedIndex() == STRING_INDEX) {
					entries.add(_entryFields[i].getText());
				}
			}
		}

		return entries.toArray();
	}

	/**
	 * Return the first entry of the fields.
	 * 
	 * @return
	 */
	public Object getFirstEntry() {
		if (!_entryFields[0].getText().isEmpty()) {
			if (_optionBoxes[0].getSelectedIndex() == DOUBLE_INDEX) {
				try {
					return Double.parseDouble(_entryFields[0].getText());
				} catch (Exception e) {
					return 0;
				}
			}
			if (_optionBoxes[0].getSelectedIndex() == STRING_INDEX) {
				return _entryFields[0].getText();
			}
		}

		return null;
	}

	/**
	 * Enable the first {@code n} fields for input. The others are disabled.
	 * 
	 * @param n
	 */
	public void enableInputFields(int n) {
		for (int i = 0; i < NUM_ENTRIES; i++) {
			_optionBoxes[i].setEnabled(i < n);
			_entryFields[i].setEnabled(i < n);
		}
	}
}


<|start_filename|>src/com/mathworks/jmi/NativeMatlab.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package com.mathworks.jmi;

/**
 * A partial stubbed out implementation of the NativeMatlab class with the method's used by matlabcontrol. This stub
 * exists so that matlabcontrol can compile against this library. At runtime this library is not referenced, instead the
 * jmi.jar on MATLAB's classpath is used. The build script for matlabcontrol intentionally does not include this
 * library in the distribution folder it generates.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class NativeMatlab {
	public static boolean nativeIsMatlabThread() {
		throw new UnsupportedOperationException("stub");
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabFunction.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Information about a MATLAB function.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MatlabFunction {
	/**
	 * Either the name of a MATLAB function or a path to a MATLAB function. The value provided to this element is
	 * resolved in the following order:
	 * <ol>
	 * <li><b>Valid MATLAB function name</b><br/>
	 *     The value will be treated as a function on MATLAB's path. Whether a function with the specified name is
	 *     actually on MATLAB's path will not be confirmed.</li>
	 * <li><b>Absolute path to an m-file</b><br/>
	 *     The value will be treated as the location of an m-file. The file's existence will be confirmed.</li>
	 * <li><b>Relative path to an m-file</b><br/>
	 *     The value will be treated as the location of an m-file relative to the root directory of the interface which
	 *     declared the method being annotated. For example if the interface is {@code com.example.MyInterface} located
	 *     at {@code /projects/code/numera/com/example/MyInterface.java} then path will be resolved relative to
	 *     {@code /projects/code/numera/}. This path can be resolved properly when both the interface and m-file are
	 *     inside of a zip file such as a jar or war file. The file's existence will be confirmed.</li>
	 * </ol>
	 * The validity of this element's value will be determined when the interface containing the method being annotated
	 * is provided to {@link MatlabFunctionLinker#link(java.lang.Class, matlabcontrol.MatlabProxy)}.
	 * 
	 * @return 
	 */
	String value();
}


<|start_filename|>src/matlabcontrol/link/UnsupportedReturnException.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * Thrown if a MATLAB type cannot be returned from MATLAB to Java because it is not supported.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class UnsupportedReturnException extends RuntimeException {
	private static final long serialVersionUID = 0xF500L;

	UnsupportedReturnException(String msg) {
		super(msg);
	}
}


<|start_filename|>src/matlabcontrol/MatlabClassLoaderHelper.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * Configures class loading inside of MATLAB such that it will work properly with RMI.
 * <br><br>
 * MATLAB uses {@code com.mathworks.jmi.CustomURLClassLoader} to load classes. Class loaders first ask their parent
 * class loader to attempt to load the class and so on up the chain all the way to the system class loader. (This is by
 * convention, one which {@code CustomURLClassLoader} follows). All classes listed on MATLAB's static class path
 * (defined in the {@code matlabroot/toolbox/local/classpath.txt} file where {@code matlabroot} is the location of
 * MATLAB) will be known to the system class loader. As such, all Java classes listed on the static class path will
 * be loaded by the system class loader. Classes listed on MATLAB's dynamic class path via the {@code javaaddpath}
 * function will be loaded by {@code CustomURLClassLoader}.
 * <br><br>
 * When matlabcontrol is started outside MATLAB and launches a session of MATLAB it adds itself to MATLAB's dynamic
 * classpath. This allows matlabcontrol's code to run inside of MATLAB without needing to find and then modify the
 * classpath.txt file (which also very well might not be desired by the user). When matlabcontrol is started inside
 * MATLAB the user may have placed it on either the static or dynamic class path (the user could do both, but the
 * static class path would be used and the dynamic would be ignored). matlabcontrol cannot initially control which
 * class loader knows about matlabcontrol.
 * <br><br>
 * The reason all of this matters is because of how RMI loads classes. When RMI attempts to load a class it starts by
 * asking the current thread for its class loader (@code Thread#getContextClassLoader}. (If that does not work it can
 * then attempt to load the class from a remote location, but this feature is not used by matlabcontrol and so this
 * step does not occur.) The class loader that is returned by the thread RMI is running on will not be MATLAB's
 * {@code CustomURLClassLoader}. As such, RMI will not operate properly if matlabcontrol was added to the dynamic class
 * path.
 * <br><br>
 * When a class loader is attempting to load a class, it starts with its parent class loader and so on up the chain. By
 * informing the system class loader of the location of matlabcontrol, then RMI's class loader will be able to find the
 * matlabcontrol classes. This can be done via reflection (see {@link #addToSystemClassLoader()}. Once the
 * system class  loader knows about the classes in matlabcontrol it will load the classes. If classes have been loaded
 * by the {@code CustomURLClassLoader} then problems can arise. The classes loaded by the system class loader and those
 * loaded by {@code CustomURLClassLoader} will exist in separate <strong>runtime</strong> packages, meaning they can
 * only access public classes, methods, and fields of one another.
 * <br><br>
 * {@code MatlabClassLoaderHelper} manipulates class loading. If the system class loader knows about matlabcontrol
 * then no action is taken. Otherwise, the system class loader is told about matlabcontrol. When matlabcontrol launches
 * a session of MATLAB this class is called before any other class is loaded, and this class is never used again. As
 * such, if this class is loaded by the {@code CustomURLClassLoader}, it will not be a problem.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabClassLoaderHelper {
	/**
	 * Configures class loading to work properly with RMI inside MATLAB. See the class description for more detail.
	 * Called from within MATLAB when {@link RemoteMatlabProxyFactory} launches a session of MATLAB.
	 * 
	 * @throws MatlabConnectionException 
	 */
	public static void configureClassLoading() throws MatlabConnectionException {
		if (!isOnSystemClassLoader()) {
			addToSystemClassLoader();
		}
	}

	/**
	 * Determines if matlabcontrol is on the system class loader's class path.
	 * 
	 * @return
	 * @throws MatlabConnectionException 
	 */
	private static boolean isOnSystemClassLoader() throws MatlabConnectionException {
		try {
			URI matlabcontrolLocation = MatlabClassLoaderHelper.class.getProtectionDomain().getCodeSource().getLocation().toURI();

			URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
			URL[] urls = systemClassLoader.getURLs();

			for (URL url : urls) {
				if (url.toURI().equals(matlabcontrolLocation)) {
					return true;
				}
			}
			return false;
		} catch (ClassCastException e) {
			throw new MatlabConnectionException("Unable to determine if matlabcontrol is on the system class loader's classpath", e);
		} catch (URISyntaxException e) {
			throw new MatlabConnectionException("Unable to determine if matlabcontrol is on the system class loader's classpath", e);
		}
	}

	/**
	 * Adds the location where matlabcontrol exists to the system class loader.
	 * 
	 * @throws MatlabConnectionException 
	 */
	private static void addToSystemClassLoader() throws MatlabConnectionException {
		URL matlabcontrolLocation = MatlabClassLoaderHelper.class.getProtectionDomain().getCodeSource().getLocation();

		try {
			URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
			Class<URLClassLoader> classLoaderClass = URLClassLoader.class;

			Method method = classLoaderClass.getDeclaredMethod("addURL", URL.class);
			method.setAccessible(true);
			method.invoke(systemClassLoader, matlabcontrolLocation);
		} catch (Exception e) {
			throw new MatlabConnectionException("Unable to add matlabcontrol to system class loader", e);
		}
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabVariable.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;

/**
 * Represents a variable in MATLAB. The representation is not associated with a given session of MATLAB. An instance of
 * this class with a given name does not mean that a variable with that name exists in any session of MATLAB.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabVariable extends MatlabType {
	private final String _name;

	/**
	 * Constructs a representation of a MATLAB variable with the name specified by {@code name}.
	 * 
	 * @param name 
	 * @throws IllegalArgumentException if {@code name} is not a valid MATLAB variable name
	 */
	public MatlabVariable(String name) {
		//Validate variable name
		if (name.isEmpty()) {
			throw new IllegalArgumentException("Invalid MATLAB variable name: " + name);
		}
		char[] nameChars = name.toCharArray();
		if (!Character.isLetter(nameChars[0])) {
			throw new IllegalArgumentException("Invalid MATLAB variable name: " + name);
		}
		for (char element : nameChars) {
			if (!(Character.isLetter(element) || Character.isDigit(element) || element == '_')) {
				throw new IllegalArgumentException("Invalid MATLAB variable name: " + name);
			}
		}
		_name = name;
	}

	/**
	 * The name of this variable.
	 * 
	 * @return 
	 */
	public String getName() {
		return _name;
	}

	/**
	 * Returns a brief description of this variable. The exact details of this representation are unspecified and are
	 * subject to change.
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "[" + this.getClass().getName() + " name=" + _name + "]";
	}

	/**
	 * Returns {@code true} if and only if {@code obj} is a {@code MatlabVariable} and has the same name as this
	 * variable.
	 * 
	 * @param obj
	 * @return 
	 */
	@Override
	public boolean equals(Object obj) {
		boolean equal = false;

		if (obj instanceof MatlabVariable) {
			MatlabVariable other = (MatlabVariable) obj;
			equal = other._name.equals(_name);
		}

		return equal;
	}

	/**
	 * Returns a hash code consistent with {@link #equals(java.lang.Object)}.
	 * 
	 * @return 
	 */
	@Override
	public int hashCode() {
		return _name.hashCode();
	}

	static class MatlabVariableGetter implements MatlabTypeGetter<MatlabVariable> {
		private static final long serialVersionUID = 7724337165919355824L;
		private String _name;
		private boolean _retrieved;

		@Override
		public MatlabVariable retrieve() {
			if (!_retrieved) {
				throw new IllegalStateException("variable not retrieved");
			}

			return new MatlabVariable(_name);
		}

		@Override
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			_name = variableName;
			_retrieved = true;
		}
	}

	@Override
	MatlabTypeSetter getSetter() {
		return new MatlabVariableSetter(_name);
	}

	private static class MatlabVariableSetter implements MatlabTypeSetter {
		private static final long serialVersionUID = -2208485477826441076L;
		private final String _name;

		private MatlabVariableSetter(String name) {
			_name = name;
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			ops.eval(variableName + " = " + _name + ";");
		}
	}
}


<|start_filename|>src/matlabcontrol/link/BaseArray.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * 
 * @param <L> underlying linear array - single dimensional array type, ex. {@code byte[]}
 * @param <T> output array - primitive numeric array type, ex. {@code byte[][][]}
 *            (1 or more dimensions is acceptable, including for example {@code byte[]})
 */
abstract class BaseArray<L, T> {
	/**
	 * Returns {@code true} if the array has no imaginary values, {@code false} otherwise. Equivalent to the MATLAB
	 * {@code isreal} function.
	 * 
	 * @return 
	 */
	abstract boolean isReal();

	/**
	 * The number of elements in the array. Zero elements are counted. The real and imaginary components of a number are
	 * together considered one element. This is equivalent to MATLAB's {@code numel} function.
	 * 
	 * @return number of elements
	 */
	abstract int getNumberOfElements();

	/**
	 * Returns the length of the dimension specified by {@code dimension}. Dimensions use 0-based indexing. So the
	 * first dimension, which is dimension 0, is the row length. The second dimension is the column length. The third
	 * dimension and beyond are pages.
	 * 
	 * @param dimension
	 * @return length of {@code dimension}
	 * @throws IllegalArgumentException if {@code dimension} is not a dimension of the array
	 */
	abstract int getLengthOfDimension(int dimension);

	/**
	 * Returns the number of dimensions of the array.
	 * 
	 * @return number of dimensions
	 */
	abstract int getNumberOfDimensions();

	/**
	 * Returns an array that holds the real values from the MATLAB array. Each call returns a new copy which may be used
	 * in any manner; modifications to it will have no effect on this instance.
	 * 
	 * @return real array
	 */
	abstract T toRealArray();

	/**
	 * Returns an array that holds the imaginary values from the MATLAB array. Each call returns a new copy which may be
	 * used in any manner; modifications to it will have no effect on this instance. If this array is real then the
	 * returned array will be have the default value as all of its base elements.
	 * 
	 * @return imaginary array
	 */
	abstract T toImaginaryArray();

	/**
	 * If this array has a sparse representation.
	 * 
	 * @return 
	 */
	abstract boolean isSparse();
}


<|start_filename|>src/matlabcontrol/link/InvocationInfo.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * A holder of information about the Java method and the associated MATLAB function.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class InvocationInfo implements Serializable {
	private static final long serialVersionUID = 764281612994597133L;

	/**
	 * The name of the function.
	 */
	final String name;

	/**
	 * The directory containing the function. This is an absolute path to an m-file on the system, never inside of
	 * a compressed file such as a jar. {@code null} if the function is (supposed to be) on MATLAB's path.
	 */
	final String containingDirectory;

	/**
	 * The types of each returned argument. The length of this array is the nargout to call the function with.
	 */
	final Class<?>[] returnTypes;

	/**
	 * Array of generic type parameters of the return types. For instance for return type at index <i>i</i> in
	 * {@code returnTypes} the generic parameters are in the array returned by {@code returnTypeGenericParameters}
	 * at index <i>i</i>.
	 */
	final Class<?>[][] returnTypeParameters;

	static InvocationInfo getInvocationInfo(Method method, MatlabFunction annotation) {
		FunctionInfo funcInfo = getFunctionInfo(method, annotation);
		ReturnTypeInfo returnInfo = getReturnTypes(method);
		InvocationInfo invocationInfo = new InvocationInfo(funcInfo.name, funcInfo.containingDirectory,
				returnInfo.returnTypes, returnInfo.returnTypeParameters);

		return invocationInfo;
	}

	InvocationInfo(String name, String containingDirectory, Class<?>[] returnTypes, Class<?>[][] returnTypeParameters) {
		this.name = name;
		this.containingDirectory = containingDirectory;

		this.returnTypes = returnTypes;
		this.returnTypeParameters = returnTypeParameters;
	}

	@Override
	public String toString() {
		StringBuilder genericParameters = new StringBuilder();
		genericParameters.append("[");
		for (int i = 0; i < returnTypeParameters.length; i++) {
			genericParameters.append(classArrayToString(returnTypeParameters[i]));

			if (i != returnTypeParameters.length - 1) {
				genericParameters.append(" ");
			}
		}
		genericParameters.append("]");

		return "[" + this.getClass().getSimpleName() +
				" name=" + name + "," +
				" containingDirectory=" + containingDirectory + "," +
				" returnTypes=" + classArrayToString(returnTypes) + "," +
				" returnTypesGenericParameters=" + genericParameters + "]";
	}

	private static String classArrayToString(Class<?>[] array) {
		StringBuilder str = new StringBuilder();
		str.append("[");
		for (int i = 0; i < array.length; i++) {
			str.append(array[i].getCanonicalName());

			if (i != array.length - 1) {
				str.append(" ");
			}
		}
		str.append("]");
		return str.toString();
	}

	private static class FunctionInfo {
		final String name;
		final String containingDirectory;

		public FunctionInfo(String name, String containingDirectory) {
			this.name = name;
			this.containingDirectory = containingDirectory;
		}
	}

	private static FunctionInfo getFunctionInfo(Method method, MatlabFunction annotation) {
		//Determine the function's name and if applicable, the directory the function is located in
		String functionName;
		String containingDirectory;

		//If a function name
		if (isFunctionName(annotation.value())) {
			functionName = annotation.value();
			containingDirectory = null;
		}
		//If a path
		else {
			String path = annotation.value();

			//Retrieve location of function file
			File functionFile;
			if (new File(path).isAbsolute()) {
				functionFile = new File(path);
			} else {
				functionFile = resolveRelativePath(method, path);
			}

			//Resolve canonical path
			try {
				functionFile = functionFile.getCanonicalFile();
			} catch (IOException e) {
				throw new LinkingException("Unable to resolve canonical path of specified function\n" +
						"method: " + method.getName() + "\n" +
						"path:" + path + "\n" +
						"non-canonical path: " + functionFile.getAbsolutePath(), e);
			}

			//Validate file location
			if (!functionFile.exists()) {
				throw new LinkingException("Specified file does not exist\n" +
						"method: " + method.getName() + "\n" +
						"path: " + path + "\n" +
						"resolved as: " + functionFile.getAbsolutePath());
			}
			if (!functionFile.isFile()) {
				throw new LinkingException("Specified file is not a file\n" +
						"method: " + method.getName() + "\n" +
						"path: " + path + "\n" +
						"resolved as: " + functionFile.getAbsolutePath());
			}
			if (!(functionFile.getName().endsWith(".m") || functionFile.getName().endsWith(".p"))) {
				throw new LinkingException("Specified file does not end in .m or .p\n" +
						"method: " + method.getName() + "\n" +
						"path: " + path + "\n" +
						"resolved as: " + functionFile.getAbsolutePath());
			}

			//Parse out the name of the function and the directory containing it
			containingDirectory = functionFile.getParent();
			functionName = functionFile.getName().substring(0, functionFile.getName().length() - 2);

			//Validate the function name
			if (!isFunctionName(functionName)) {
				throw new LinkingException("Specified file's name is not a MATLAB function name\n" +
						"Function Name: " + functionName + "\n" +
						"File: " + functionFile.getAbsolutePath());
			}
		}

		return new FunctionInfo(functionName, containingDirectory);
	}

	private static boolean isFunctionName(String functionName) {
		boolean isFunctionName = true;

		char[] nameChars = functionName.toCharArray();

		if (!Character.isLetter(nameChars[0])) {
			isFunctionName = false;
		} else {
			for (char element : nameChars) {
				if (!(Character.isLetter(element) || Character.isDigit(element) || element == '_')) {
					isFunctionName = false;
					break;
				}
			}
		}

		return isFunctionName;
	}

	/**
	 * Cache used by {@link #resolveRelativePath(Method, String)}
	 */
	private static final ConcurrentHashMap<Class<?>, Map<String, File>> UNZIPPED_ENTRIES = new ConcurrentHashMap<Class<?>, Map<String, File>>();

	/**
	 * Resolves the location of {@code relativePath} relative to the interface which declared {@code method}. If the
	 * interface is inside of a zip file (jar/war/ear etc. file) then the contents of the zip file may first need to be
	 * unzipped.
	 * 
	 * @param method
	 * @param relativePath
	 * @return the absolute location of the file
	 */
	private static File resolveRelativePath(Method method, String relativePath) {
		Class<?> theInterface = method.getDeclaringClass();
		File interfaceLocation = getClassLocation(theInterface);

		File functionFile;

		//Code source is in a file, which means it should be jar/ear/war/zip etc.
		if (interfaceLocation.isFile()) {
			if (!UNZIPPED_ENTRIES.containsKey(theInterface)) {
				UnzipResult unzipResult = unzip(interfaceLocation);
				Map<String, File> mapping = unzipResult.unzippedMapping;
				List<File> filesToDelete = new ArrayList<File>(mapping.values());
				filesToDelete.add(unzipResult.rootDirectory);

				//If there was a previous mapping, delete all of the files just unzipped 
				if (UNZIPPED_ENTRIES.putIfAbsent(theInterface, mapping) != null) {
					deleteFiles(filesToDelete, true);
				}
				//No previous mapping, delete unzipped files on JVM exit
				else {
					deleteFiles(filesToDelete, false);
				}
			}

			functionFile = UNZIPPED_ENTRIES.get(theInterface).get(relativePath);

			if (functionFile == null) {
				throw new LinkingException("Unable to find file inside of zip\n" +
						"Method: " + method.getName() + "\n" +
						"Relative Path: " + relativePath + "\n" +
						"Zip File: " + interfaceLocation.getAbsolutePath());
			}
		}
		//Code source is a directory, it code should not be inside a jar/ear/war/zip etc.
		else {
			functionFile = new File(interfaceLocation, relativePath);
		}

		return functionFile;
	}

	private static void deleteFiles(Collection<File> files, boolean deleteNow) {
		ArrayList<File> sortedFiles = new ArrayList<File>(files);
		Collections.sort(sortedFiles);

		//Delete files in the opposite order so that files are deleted before their containing directories
		if (deleteNow) {
			for (int i = sortedFiles.size() - 1; i >= 0; i--) {
				boolean deleted = sortedFiles.get(i).delete();
				if (!deleted) {
					System.err.println("unable to delete " + sortedFiles.get(i));
				}
			}
		}
		//Delete files in the existing order because the files will be deleted on exit in the opposite order
		else {
			for (File file : sortedFiles) {
				file.deleteOnExit();
			}
		}
	}

	/**
	 * Cache used by {@link #getClassLocation(java.lang.Class)}}.
	 */
	private static final ConcurrentHashMap<Class<?>, File> CLASS_LOCATIONS = new ConcurrentHashMap<Class<?>, File>();

	private static File getClassLocation(Class<?> clazz) {
		File result = CLASS_LOCATIONS.get(clazz);
		if (result != null) {
			return result;
		} else {
			try {
				URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
				File file = new File(url.toURI().getPath()).getCanonicalFile();
				if (!file.exists()) {
					throw new LinkingException("Incorrectly resolved location of class\n" +
							"class: " + clazz.getCanonicalName() + "\n" +
							"location: " + file.getAbsolutePath());
				}
				return CLASS_LOCATIONS.putIfAbsent(clazz, file);
			} catch (IOException e) {
				throw new LinkingException("Unable to determine location of " + clazz.getCanonicalName(), e);
			} catch (URISyntaxException e) {
				throw new LinkingException("Unable to determine location of " + clazz.getCanonicalName(), e);
			}
		}
	}

	private static class UnzipResult {
		final Map<String, File> unzippedMapping;
		File rootDirectory;

		private UnzipResult(Map<String, File> mapping, File root) {
			this.unzippedMapping = mapping;
			this.rootDirectory = root;
		}
	}

	/**
	 * Unzips the file located at {@code zipLocation}.
	 * 
	 * @param zipLocation the location of the file zip
	 * @return resulting files from unzipping
	 * @throws LinkingException if unable to unzip the zip file for any reason
	 */
	private static UnzipResult unzip(File zipLocation) {
		ZipFile zip;
		try {
			zip = new ZipFile(zipLocation);
		} catch (IOException e) {
			throw new LinkingException("Unable to open zip file\n" +
					"zip location: " + zipLocation.getAbsolutePath(), e);
		}

		try {
			//Mapping from entry names to the unarchived location on disk
			Map<String, File> entryMap = new HashMap<String, File>();

			//Destination
			File unzipDir = new File(System.getProperty("java.io.tmpdir"), "linked_" + UUID.randomUUID().toString());

			for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();) {
				ZipEntry entry = entries.nextElement();

				//Directory
				if (entry.isDirectory()) {
					File destDir = new File(unzipDir, entry.getName());
					boolean mkdir = destDir.mkdirs();
					if (!mkdir) {
						System.err.println("Unable to mkdir " + destDir);
					}

					entryMap.put(entry.getName(), destDir);
				}
				//File
				else {
					//File should not exist, but confirm it
					File destFile = new File(unzipDir, entry.getName());
					if (destFile.exists()) {
						throw new LinkingException("Cannot unzip file, randomly generated path already exists\n" +
								"generated path: " + destFile.getAbsolutePath() + "\n" +
								"zip file: " + zipLocation.getAbsolutePath());
					}
					boolean mkdir = destFile.getParentFile().mkdirs();
					if (!mkdir) {
						System.err.println("Unable to mkdir " + destFile.getParentFile());
					}

					//Unarchive
					try {
						final int BUFFER_SIZE = 2048;
						OutputStream dest = new BufferedOutputStream(new FileOutputStream(destFile), BUFFER_SIZE);
						try {
							InputStream entryStream = zip.getInputStream(entry);
							try {
								byte[] buffer = new byte[BUFFER_SIZE];
								int count;
								while ((count = entryStream.read(buffer, 0, BUFFER_SIZE)) != -1) {
									dest.write(buffer, 0, count);
								}
								dest.flush();
							} finally {
								entryStream.close();
							}
						} finally {
							dest.close();
						}
					} catch (IOException e) {
						throw new LinkingException("Unable to unzip file entry\n" +
								"entry: " + entry.getName() + "\n" +
								"zip location: " + zipLocation.getAbsolutePath() + "\n" +
								"destination file: " + destFile.getAbsolutePath(), e);
					}

					entryMap.put(entry.getName(), destFile);
				}
			}

			return new UnzipResult(Collections.unmodifiableMap(entryMap), unzipDir);
		} finally {
			try {
				zip.close();
			} catch (IOException ex) {
				throw new LinkingException("Unable to close zip file: " + zipLocation.getAbsolutePath(), ex);
			}
		}
	}

	private static class ReturnTypeInfo {
		Class<?>[] returnTypes;
		Class<?>[][] returnTypeParameters;

		private ReturnTypeInfo(Class<?>[] returnTypes, Class<?>[][] returnTypeParameters) {
			this.returnTypes = returnTypes;
			this.returnTypeParameters = returnTypeParameters;
		}
	}

	private static ReturnTypeInfo getReturnTypes(Method method) {
		//The type-erasured return type of the method
		Class<?> methodReturn = method.getReturnType();

		//The return type of the method with type information
		Type genericReturn = method.getGenericReturnType();

		//The return types to be determined
		Class<?>[] returnTypes;
		Class<?>[][] returnTypeGenericParameters;

		//0 return arguments
		if (methodReturn.equals(void.class)) {
			returnTypes = new Class<?>[0];
			returnTypeGenericParameters = new Class<?>[0][0];
		}
		//1 return argument
		else if (!MatlabReturns.ReturnN.class.isAssignableFrom(methodReturn)) {
			//MatlabNumberArray subclasses are allowed to be parameterized
			if (MatlabNumberArray.class.isAssignableFrom(methodReturn)) {
				if (genericReturn instanceof ParameterizedType) {
					Type[] parameterizedTypes = ((ParameterizedType) genericReturn).getActualTypeArguments();
					Class<?> parameter = getMatlabNumberArrayParameter(parameterizedTypes[0], methodReturn, method);
					returnTypeGenericParameters = new Class<?>[][]{{parameter}};
				} else {
					throw new LinkingException(method + " must parameterize " + methodReturn.getCanonicalName());
				}
			} else if (!methodReturn.equals(genericReturn)) {
				throw new LinkingException(method + " may not have a return type that uses generics");
			} else {
				returnTypeGenericParameters = new Class<?>[1][0];
			}

			returnTypes = new Class<?>[]{methodReturn};
		}
		//2 or more return arguments
		else {
			if (genericReturn instanceof ParameterizedType) {
				Type[] parameterizedTypes = ((ParameterizedType) genericReturn).getActualTypeArguments();
				returnTypes = new Class<?>[parameterizedTypes.length];
				returnTypeGenericParameters = new Class<?>[parameterizedTypes.length][];

				for (int i = 0; i < parameterizedTypes.length; i++) {
					Type type = parameterizedTypes[i];

					if (type instanceof Class) {
						Class<?> returnType = (Class<?>) type;
						if (MatlabNumberArray.class.isAssignableFrom(returnType)) {
							throw new LinkingException(method + " must parameterize " + returnType.getCanonicalName());
						}
						returnTypes[i] = returnType;
						returnTypeGenericParameters[i] = new Class[0];
					} else if (type instanceof GenericArrayType) {
						returnTypes[i] = getClassOfArrayType((GenericArrayType) type, method);
						returnTypeGenericParameters[i] = new Class[0];
					} else if (type instanceof ParameterizedType) {
						//MatlabNumberArray subclasses are allowed to be parameterized
						ParameterizedType parameterizedType = (ParameterizedType) type;
						Type rawType = parameterizedType.getRawType();
						if (rawType instanceof Class && MatlabNumberArray.class.isAssignableFrom((Class<?>) rawType)) {
							Class<?> returnType = (Class<?>) rawType;
							returnTypes[i] = returnType;

							Class<?> parameter = getMatlabNumberArrayParameter(
									parameterizedType.getActualTypeArguments()[0], returnType, method);
							returnTypeGenericParameters[i] = new Class[]{parameter};
						} else {
							throw new LinkingException(method + " may not parameterize " +
									methodReturn.getCanonicalName() + " with a parameterized type");
						}
					} else if (type instanceof WildcardType) {
						throw new LinkingException(method + " may not parameterize " + methodReturn.getCanonicalName() +
								" with a wild card type");
					} else if (type instanceof TypeVariable) {
						throw new LinkingException(method + " may not parameterize " + methodReturn.getCanonicalName() +
								" with a generic type");
					} else {
						throw new LinkingException(method + " may not parameterize " + methodReturn.getCanonicalName() +
								" with " + type);
					}
				}
			} else {
				throw new LinkingException(method + " must parameterize " + methodReturn.getCanonicalName());
			}
		}

		return new ReturnTypeInfo(returnTypes, returnTypeGenericParameters);
	}

	private static Class<?> getMatlabNumberArrayParameter(Type type, Class<?> matlabArrayClass, Method method) {
		Class<?> parameter;
		if (type instanceof GenericArrayType) {
			parameter = getClassOfArrayType((GenericArrayType) type, method);
			ClassInfo paramInfo = ClassInfo.getInfo(parameter);

			boolean validParameter = ((matlabArrayClass.equals(MatlabInt8Array.class) && byte.class.equals(paramInfo.baseComponentType)) ||
					(matlabArrayClass.equals(MatlabInt16Array.class) && short.class.equals(paramInfo.baseComponentType)) ||
					(matlabArrayClass.equals(MatlabInt32Array.class) && int.class.equals(paramInfo.baseComponentType)) ||
					(matlabArrayClass.equals(MatlabInt64Array.class) && long.class.equals(paramInfo.baseComponentType)) ||
					(matlabArrayClass.equals(MatlabSingleArray.class) && float.class.equals(paramInfo.baseComponentType)) ||
					(matlabArrayClass.equals(MatlabDoubleArray.class) && double.class.equals(paramInfo.baseComponentType)));

			if (!validParameter) {
				throw new LinkingException(method + " may not parameterize " + matlabArrayClass.getCanonicalName() +
						" with " + parameter.getCanonicalName());
			}
		} else {
			throw new LinkingException(method + " may not parameterize " + matlabArrayClass.getCanonicalName() +
					" with " + type);
		}

		return parameter;
	}

	/**
	 * 
	 * @param type
	 * @param method used for exception message only
	 * @return 
	 */
	private static Class<?> getClassOfArrayType(GenericArrayType type, Method method) {
		int dimensions = 1;
		Type componentType = type.getGenericComponentType();
		while (!(componentType instanceof Class)) {
			dimensions++;
			if (componentType instanceof GenericArrayType) {
				componentType = ((GenericArrayType) componentType).getGenericComponentType();
			} else if (componentType instanceof TypeVariable) {
				throw new LinkingException(method + " may not parameterize " +
						method.getReturnType().getCanonicalName() + " with a generic array");
			} else {
				throw new LinkingException(method + " may not parameterize " +
						method.getReturnType().getCanonicalName() + " with an array of type " + type);
			}
		}

		return ArrayUtils.getArrayClass((Class<?>) componentType, dimensions);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabNonNumericMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * 
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
abstract class MatlabNonNumericMatrix<L, T> extends MatlabMatrix<L, T> {
	/**
	 * Returns an array that holds the values from the MATLAB matrix. Each call returns a new copy which may be used in
	 * any manner; modifications to it will have no effect on this instance.
	 * 
	 * @return array
	 */
	public T toArray() {
		return getBaseArray().toRealArray();
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabInt32Array.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.Arrays;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @param <M> {@code int} array type, ex. {@code int[]}, {@code int[][]}, {@code int[][][]}, ...
 */
public class MatlabInt32Array<T> extends MatlabNumberArray<int[], T> {
	MatlabInt32Array(int[] real, int[] imag, int[] lengths) {
		super(int[].class, real, imag, lengths);
	}

	public static <T> MatlabInt32Array<T> getInstance(T real, T imaginary) {
		return new MatlabInt32Array<T>(real, imaginary);
	}

	private MatlabInt32Array(T real, T imaginary) {
		super(int[].class, real, imaginary);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt32 getElementAtLinearIndex(int index) {
		return new MatlabInt32(_real[index], (_imag == null ? 0 : _imag[index]));
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws IllegalArgumentException {@inheritDoc}
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt32 getElementAtIndices(int row, int column, int... pages) {
		int linearIndex = getLinearIndex(row, column, pages);

		return new MatlabInt32(_real[linearIndex], (_imag == null ? 0 : _imag[linearIndex]));
	}

	@Override
	boolean equalsRealArray(int[] other) {
		return Arrays.equals(_real, other);
	}

	@Override
	boolean equalsImaginaryArray(int[] other) {
		return Arrays.equals(_imag, other);
	}

	@Override
	int hashReal() {
		return Arrays.hashCode(_real);
	}

	@Override
	int hashImaginary() {
		return Arrays.hashCode(_imag);
	}

	@Override
	boolean containsNonZero(int[] array) {
		boolean contained = false;

		for (int val : array) {
			if (val != 0) {
				contained = true;
				break;
			}
		}

		return contained;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * The base class for all MATLAB matrices.
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
abstract class MatlabMatrix<L, T> {
	abstract BaseArray<L, T> getBaseArray();

	/**
	 * The number of elements in the array. The real and imaginary components of a number are together considered one
	 * element. This is equivalent to MATLAB's {@code numel} function.
	 * 
	 * @return number of elements
	 */
	public int getNumberOfElements() {
		return getBaseArray().getNumberOfDimensions();
	}

	/**
	 * Returns the length of the dimension specified by {@code dimension}. Dimensions use 0-based indexing. So the
	 * first dimension, which is dimension 0, is the row length. The second dimension is the column length. The third
	 * dimension and beyond are pages.
	 * 
	 * @param dimension
	 * @return length of {@code dimension}
	 * @throws IllegalArgumentException if {@code dimension} is not a dimension of the array
	 */
	public int getLengthOfDimension(int dimension) {
		return getBaseArray().getLengthOfDimension(dimension);
	}

	/**
	 * Returns the number of dimensions of the array.
	 * 
	 * @return number of dimensions
	 */
	public int getNumberOfDimensions() {
		return getBaseArray().getNumberOfDimensions();
	}
}


<|start_filename|>src/matlabcontrol/MatlabSessionImpl.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.rmi.registry.Registry;
import java.util.UUID;

/**
 * Implementation of {@link MatlabSession}. Split into interface and implementation to work properly with RMI.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabSessionImpl implements MatlabSession {
	/**
	 * The prefix for all RMI names of bound instances of {@link MatlabSession}.
	 */
	private static final String MATLAB_SESSION_PREFIX = "MATLAB_SESSION_";

	/**
	 * The bound name in the RMI registry for this instance.
	 */
	private final String SESSION_ID = MATLAB_SESSION_PREFIX + UUID.randomUUID().toString();

	@Override
	public synchronized boolean connectFromRMI(String receiverID, int port) {
		boolean success = false;
		if (MatlabConnector.isAvailableForConnection()) {
			MatlabConnector.connect(receiverID, port, true);
			success = true;
		}

		return success;
	}

	/**
	 * The unique identifier for this session.
	 * 
	 * @return 
	 */
	String getSessionID() {
		return SESSION_ID;
	}

	/**
	 * Attempts to connect to a running instance of MATLAB. Returns {@code true} if a connection was made,
	 * {@code false} otherwise.
	 * 
	 * @param receiverID
	 * @param port
	 * @return if connection was made
	 */
	static boolean connectToRunningSession(String receiverID, int port) {
		boolean establishedConnection = false;

		try {
			Registry registry = LocalHostRMIHelper.getRegistry(port);

			String[] remoteNames = registry.list();
			for (String name : remoteNames) {
				if (name.startsWith(MATLAB_SESSION_PREFIX)) {
					MatlabSession session = (MatlabSession) registry.lookup(name);
					if (session.connectFromRMI(receiverID, port)) {
						establishedConnection = true;
						break;
					}
				}
			}
		} catch (Exception e) {}

		return establishedConnection;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabInt8Array.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.Arrays;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @param <T> {@code byte} array type, ex. {@code byte[]}, {@code byte[][]}, {@code byte[][][]}, ...
 */
public class MatlabInt8Array<T> extends MatlabNumberArray<byte[], T> {
	MatlabInt8Array(byte[] real, byte[] imag, int[] lengths) {
		super(byte[].class, real, imag, lengths);
	}

	public static <T> MatlabInt8Array<T> getInstance(T real, T imaginary) {
		return new MatlabInt8Array<T>(real, imaginary);
	}

	private MatlabInt8Array(T real, T imaginary) {
		super(byte[].class, real, imaginary);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt8 getElementAtLinearIndex(int index) {
		return new MatlabInt8(_real[index], (_imag == null ? 0 : _imag[index]));
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws IllegalArgumentException {@inheritDoc}
	 * @throws ArrayIndexOutOfBoundsException {@inheritDoc}
	 */
	@Override
	public MatlabInt8 getElementAtIndices(int row, int column, int... pages) {
		int linearIndex = getLinearIndex(row, column, pages);

		return new MatlabInt8(_real[linearIndex], (_imag == null ? 0 : _imag[linearIndex]));
	}

	@Override
	boolean equalsRealArray(byte[] other) {
		return Arrays.equals(_real, other);
	}

	@Override
	boolean equalsImaginaryArray(byte[] other) {
		return Arrays.equals(_imag, other);
	}

	@Override
	int hashReal() {
		return Arrays.hashCode(_real);
	}

	@Override
	int hashImaginary() {
		return Arrays.hashCode(_imag);
	}

	@Override
	boolean containsNonZero(byte[] array) {
		boolean contained = false;

		for (byte val : array) {
			if (val != 0) {
				contained = true;
				break;
			}
		}

		return contained;
	}
}


<|start_filename|>src/matlabcontrol/MatlabInvocationException.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

/**
 * Represents a failure to invoke a method on the MATLAB session.
 * 
 * @since 3.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class MatlabInvocationException extends Exception {
	private static final long serialVersionUID = 0xB400L;

	static enum Reason {
		INTERRRUPTED("Method could not be completed because the MATLAB thread was interrupted before MATLAB returned"), PROXY_NOT_CONNECTED("The proxy is not connected to MATLAB"), UNMARSHAL("Object attempting to be received cannot be transferred between Java Virtual Machines"), MARSHAL("Object attempting to be sent cannot be transferred between Java Virtual Machines"), INTERNAL_EXCEPTION("Method did not return properly because of an internal MATLAB exception"), NARGOUT_MISMATCH("Number of arguments returned did not match excepted"), EVENT_DISPATCH_THREAD("Issue pumping Event Dispatch Thread"), RUNTIME_EXCEPTION("RuntimeException occurred in MatlabThreadCallable, see cause for more information"), UNKNOWN("Method could not be invoked for an unknown reason, see cause for more information");

		private final String _message;

		private Reason(String msg) {
			_message = msg;
		}

		MatlabInvocationException asException() {
			return new MatlabInvocationException(_message);
		}

		MatlabInvocationException asException(Throwable cause) {
			return new MatlabInvocationException(_message, cause);
		}

		MatlabInvocationException asException(String additionalInfo) {
			return new MatlabInvocationException(_message + ": " + additionalInfo);
		}

		MatlabInvocationException asException(String additionalInfo, Throwable cause) {
			return new MatlabInvocationException(_message + ": " + additionalInfo, cause);
		}
	}

	private MatlabInvocationException(String msg) {
		super(msg);
	}

	private MatlabInvocationException(String msg, Throwable cause) {
		super(msg, cause);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabDoubleMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public abstract class MatlabDoubleMatrix<T> extends MatlabNumericMatrix<double[], T> {
	MatlabDoubleMatrix() {}

	public static <T> MatlabDoubleMatrix<T> getFull(T real, T imag) {
		return new MatlabDoubleFullMatrix<T>(real, imag);
	}

	public static MatlabDoubleMatrix<double[][]> getSparse(int[] rowIndices, int[] colIndices,
			double[] real, double[] imag, int numRows, int numCols) {
		return new MatlabDoubleSparseMatrix(rowIndices, colIndices, real, imag, numRows, numCols);
	}

	public abstract double getRealElementAtLinearIndex(int linearIndex);

	public abstract double getImaginaryElementAtLinearIndex(int linearIndex);

	public abstract double getRealElementAtIndices(int row, int column);

	public abstract double getRealElementAtIndices(int row, int column, int page);

	public abstract double getRealElementAtIndices(int row, int column, int[] pages);

	public abstract double getImaginaryElementAtIndices(int row, int column);

	public abstract double getImaginaryElementAtIndices(int row, int column, int page);

	public abstract double getImaginaryElementAtIndices(int row, int column, int[] pages);

	@Override
	public abstract MatlabDouble getElementAtLinearIndex(int linearIndex);

	@Override
	public abstract MatlabDouble getElementAtIndices(int row, int column);

	@Override
	public abstract MatlabDouble getElementAtIndices(int row, int column, int page);

	@Override
	public abstract MatlabDouble getElementAtIndices(int row, int column, int... pages);
}


<|start_filename|>src/matlabcontrol/LocalHostRMIHelper.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;

/**
 * Handles creation of RMI objects, making sure they only operate on localhost.
 *
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class LocalHostRMIHelper {
	private static final LocalHostRMISocketFactory SOCKET_FACTORY = new LocalHostRMISocketFactory();

	public static Registry getRegistry(int port) throws RemoteException {
		return LocateRegistry.getRegistry("localhost", port, SOCKET_FACTORY);
	}

	public static Registry createRegistry(int port) throws RemoteException {
		return LocateRegistry.createRegistry(port, SOCKET_FACTORY, SOCKET_FACTORY);
	}

	public static Remote exportObject(Remote object) throws RemoteException {
		return UnicastRemoteObject.exportObject(object, 0, SOCKET_FACTORY, SOCKET_FACTORY);
	}

	private static class LocalHostRMISocketFactory implements RMIClientSocketFactory, RMIServerSocketFactory, Serializable {
		private static final long serialVersionUID = 2973279795727940224L;

		@Override
		public Socket createSocket(String host, int port) throws IOException {
			return SocketFactory.getDefault().createSocket(InetAddress.getByName("localhost"), port);
		}

		@Override
		public ServerSocket createServerSocket(int port) throws IOException {
			return ServerSocketFactory.getDefault().createServerSocket(port, 1, InetAddress.getByName("localhost"));
		}

		@Override
		public boolean equals(Object o) {
			return (o instanceof LocalHostRMISocketFactory);
		}

		@Override
		public int hashCode() {
			return 5;
		}

		/**
		 * Overridden to provide a better name for the RMI RenewClean thread.
		 * 
		 * @return 
		 */
		@Override
		public String toString() {
			return "MLC localhost Socket Factory";
		}
	}

	static class LocalHostRemoteObject extends UnicastRemoteObject {
		private static final long serialVersionUID = -7160502485279570444L;

		LocalHostRemoteObject() throws RemoteException {
			super(0, SOCKET_FACTORY, SOCKET_FACTORY);
		}
	}
}


<|start_filename|>src/matlabcontrol/link/ClassInfo.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class ClassInfo {
	private static ConcurrentMap<Class<?>, ClassInfo> CACHE = new ConcurrentHashMap<Class<?>, ClassInfo>();

	static ClassInfo getInfo(Class<?> clazz) {
		ClassInfo info = CACHE.get(clazz);
		if (info == null) {
			info = new ClassInfo(clazz);
			CACHE.put(clazz, info);
		}

		return info;
	}

	/**
	 * The class this information is about
	 */
	final Class<?> describedClass;

	/**
	 * If the class is either {@code void} or {@code java.lang.Void}
	 */
	final boolean isVoid;

	/**
	 * If the class is primitive
	 */
	final boolean isPrimitive;

	/**
	 * If an array type
	 */
	final boolean isArray;

	/**
	 * If the array's base component type is a primitive
	 */
	final boolean isPrimitiveArray;

	/**
	 * If the base component type of an array, {@code null} if not an array
	 */
	final Class<?> baseComponentType;

	/**
	 * The number of array dimensions, {@code 0} if not an array
	 */
	final int arrayDimensions;

	/**
	 * If the class is one of: {@code byte}, {@code Byte}, {@code short}, {@code Short}, {@code int},
	 * {@code Integer}, {@code long}, {@code Long}, {@code float}, {@code Float}, {@code double}, {@code Double}
	 */
	final boolean isBuiltinNumeric;

	/**
	 * If the class inherits from {@code MatlabType}
	 */
	final boolean isMatlabType;

	private ClassInfo(Class<?> clazz) {
		describedClass = clazz;

		isPrimitive = clazz.isPrimitive();

		if (clazz.isArray()) {
			isArray = true;

			int dim = 0;
			Class<?> type = clazz;
			while (type.isArray()) {
				dim++;
				type = type.getComponentType();
			}

			arrayDimensions = dim;
			baseComponentType = type;
			isPrimitiveArray = type.isPrimitive();
		} else {
			isArray = false;
			baseComponentType = null;
			isPrimitiveArray = false;
			arrayDimensions = 0;
		}

		isVoid = clazz.equals(Void.class) || clazz.equals(void.class);
		isMatlabType = MatlabType.class.isAssignableFrom(clazz);

		isBuiltinNumeric = clazz.equals(Byte.class) || clazz.equals(byte.class) ||
				clazz.equals(Short.class) || clazz.equals(short.class) ||
				clazz.equals(Integer.class) || clazz.equals(int.class) ||
				clazz.equals(Long.class) || clazz.equals(long.class) ||
				clazz.equals(Float.class) || clazz.equals(float.class) ||
				clazz.equals(Double.class) || clazz.equals(double.class);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabType.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

import java.io.Serializable;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;

/**
 * Superclass of all Java classes which represent MATLAB types.
 * <br><br>
 * Subclasses of this either final or abstract and non-extenable with final subclasses of their own. Being final makes
 * it easier to ensure appropriate behavior when transforming types automatically. Subclasses are not
 * {@link Serializable} to reduce the publicly exposed API and reduce the need to maintain serializable compatibility.
 * Instead, transferring occurs by use of {@link MatlabTypeSetter} and {@link MatlabTypeGetter}. A getter is typically
 * associated with a class as an inner static class.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
abstract class MatlabType {
	MatlabType() {}

	abstract MatlabTypeSetter getSetter();

	/**
	 * Retrieves in MATLAB the information necessary to create the associated {@code MatlabType} from a given MATLAB
	 * variable.
	 * <br><br>
	 * Must have an accessible no argument constructor.
	 * 
	 * @param <U> 
	 */
	static interface MatlabTypeGetter<T> extends Serializable {
		/**
		 * Takes the information retrieved by the
		 * {@link #getInMatlab(matlabcontrol.MatlabOperations, java.lang.String)} and creates the
		 * associated {@code MatlabType}.
		 * 
		 * @return 
		 */
		public T retrieve();

		/**
		 * Retrieves the data it needs from the variable in MATLAB. So that after retrieving this information
		 * {@link #retrieve()} can be called to create the appropriate {@code MatlabType}.
		 * 
		 * @param ops
		 * @param variableName 
		 */
		public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException;
	}

	/**
	 * Sets in MATLAB the equivalent of the data represented by the {@code MatlabType} that provides an instance of
	 * an implementation of this class.
	 */
	static interface MatlabTypeSetter extends Serializable {
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException;
	}
}


<|start_filename|>src/matlabcontrol/demo/InsideMatlab.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.demo;

import java.awt.EventQueue;
import java.net.URL;
import java.net.URLClassLoader;

import javax.swing.WindowConstants;

/**
 * This class exists solely as a entry point to the demo when running it from inside of MATLAB. By placing it in the
 * default package and giving it the name that it has, it means that once the code is added to MATLAB's Java classpath
 * then the demo can be launched just by typing {@code matlabcontroldemo}. Typing that will cause the constructor of
 * this class to be called.
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class InsideMatlab {
	public static void main(String[] args) {
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		URL[] urls = ((URLClassLoader) cl).getURLs();
		for (URL url : urls) {
			System.out.println(url.getFile());
		}

		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				DemoFrame frame = new DemoFrame("matlabcontrol demo - Running Inside MATLAB", null);
				frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
				frame.setVisible(true);
			}
		});
	}

	/**
	 * This method will be called by MATLAB to provide the text for the {@code ans} value. By overriding this method
	 * in this manner it will cause this method's return value to be used as a status message:
	 * <pre>
	 * {@code
	 * >> matlabcontroldemo
	 * 
	 * ans =
	 * 
	 * matlabcontrol demo launching...
	 * }
	 * </pre>
	 * 
	 * @return 
	 */
	@Override
	public String toString() {
		return "matlabcontrol demo launching...";
	}
}


<|start_filename|>src/matlabcontrol/LocalMatlabProxy.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

/**
 * Allows for calling MATLAB from <b>inside</b> of MATLAB.
 * 
 * @since 3.1.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class LocalMatlabProxy extends MatlabProxy {
	/**
	 * If connected to MATLAB.
	 * 
	 * This notion of connection exists to make it consistent with {@link RemoteMatlabProxy}, but is not actually
	 * necessary. Unless a user calls {@link #disconnect()} this proxy cannot become disconnected.
	 */
	private volatile boolean _isConnected = true;

	LocalMatlabProxy(Identifier id) {
		super(id, true);
	}

	@Override
	public boolean isRunningInsideMatlab() {
		return true;
	}

	@Override
	public boolean isConnected() {
		return _isConnected;
	}

	@Override
	public boolean disconnect() {
		_isConnected = false;

		//Notify listeners
		notifyDisconnectionListeners();

		return true;
	}

	// Methods which interact with MATLAB

	@Override
	public void exit() throws MatlabInvocationException {
		if (this.isConnected()) {
			JMIWrapper.exit();
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public void eval(String command) throws MatlabInvocationException {
		if (this.isConnected()) {
			JMIWrapper.eval(command);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public Object[] returningEval(String command, int nargout) throws MatlabInvocationException {
		if (this.isConnected()) {
			return JMIWrapper.returningEval(command, nargout);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public void feval(String functionName, Object... args) throws MatlabInvocationException {
		if (this.isConnected()) {
			JMIWrapper.feval(functionName, args);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public Object[] returningFeval(String functionName, int nargout, Object... args) throws MatlabInvocationException {
		if (this.isConnected()) {
			return JMIWrapper.returningFeval(functionName, nargout, args);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public void setVariable(String variableName, Object value) throws MatlabInvocationException {
		if (this.isConnected()) {
			JMIWrapper.setVariable(variableName, value);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public Object getVariable(String variableName) throws MatlabInvocationException {
		if (this.isConnected()) {
			return JMIWrapper.getVariable(variableName);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}

	@Override
	public <T> T invokeAndWait(MatlabThreadCallable<T> callable) throws MatlabInvocationException {
		if (this.isConnected()) {
			return JMIWrapper.invokeAndWait(callable);
		} else {
			throw MatlabInvocationException.Reason.PROXY_NOT_CONNECTED.asException();
		}
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabInt32.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * MATLAB {@code int32} with real and imaginary components.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public final class MatlabInt32 extends MatlabNumber<Integer> {
	private static final Integer DEFAULT = 0;

	public MatlabInt32(int real, int imag) {
		super(DEFAULT, real, imag);
	}

	/**
	 * Returns the real value.
	 * 
	 * @return 
	 */
	public int toReal() {
		return _real;
	}

	/**
	 * Returns the imaginary value.
	 * 
	 * @return 
	 */
	public int toImaginary() {
		return _imag;
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabDoubleFullMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabDoubleFullMatrix<T> extends MatlabDoubleMatrix<T> {
	private final FullArray<double[], T> _array;

	MatlabDoubleFullMatrix(double[] real, double[] imag, int[] dimensions) {
		_array = new FullArray<double[], T>(double[].class, real, imag, dimensions);
	}

	MatlabDoubleFullMatrix(T real, T imag) {
		_array = new FullArray<double[], T>(double[].class, real, imag);
	}

	@Override
	BaseArray<double[], T> getBaseArray() {
		return _array;
	}

	@Override
	public double getRealElementAtLinearIndex(int linearIndex) {
		return _array._real[linearIndex];
	}

	@Override
	public double getImaginaryElementAtLinearIndex(int linearIndex) {
		return _array._imag == null ? 0 : _array._imag[linearIndex];
	}

	@Override
	public double getRealElementAtIndices(int row, int column) {
		return _array._real[_array.getLinearIndex(row, column)];
	}

	@Override
	public double getRealElementAtIndices(int row, int column, int page) {
		return _array._real[_array.getLinearIndex(row, column, page)];
	}

	@Override
	public double getRealElementAtIndices(int row, int column, int[] pages) {
		return _array._real[_array.getLinearIndex(row, column, pages)];
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column) {
		return _array._imag == null ? 0 : _array._imag[_array.getLinearIndex(row, column)];
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column, int page) {
		return _array._imag == null ? 0 : _array._imag[_array.getLinearIndex(row, column, page)];
	}

	@Override
	public double getImaginaryElementAtIndices(int row, int column, int[] pages) {
		return _array._imag == null ? 0 : _array._imag[_array.getLinearIndex(row, column, pages)];
	}

	@Override
	public MatlabDouble getElementAtLinearIndex(int linearIndex) {
		return new MatlabDouble(_array._real[linearIndex], _array._imag == null ? 0 : _array._imag[linearIndex]);
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column) {
		int linearIndex = _array.getLinearIndex(row, column);

		return new MatlabDouble(_array._real[linearIndex], _array._imag == null ? 0 : _array._imag[linearIndex]);
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column, int page) {
		int linearIndex = _array.getLinearIndex(row, column, page);

		return new MatlabDouble(_array._real[linearIndex], _array._imag == null ? 0 : _array._imag[linearIndex]);
	}

	@Override
	public MatlabDouble getElementAtIndices(int row, int column, int... pages) {
		int linearIndex = _array.getLinearIndex(row, column, pages);

		return new MatlabDouble(_array._real[linearIndex], _array._imag == null ? 0 : _array._imag[linearIndex]);
	}
}


<|start_filename|>src/matlabcontrol/ProxyFactory.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import matlabcontrol.MatlabProxyFactory.Request;
import matlabcontrol.MatlabProxyFactory.RequestCallback;

/**
 * A factory which creates instances of {@link MatlabProxy}.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
interface ProxyFactory {
	/**
	 * Returns a {@link MatlabProxy}. If a connection cannot be established before the timeout then this method will end
	 * execution and an exception will be thrown. A timeout can be specified with the options provided to this factory.
	 * If no timeout was specified, then a default of 180 seconds will be used.
	 * <br><br>
	 * While this method blocks the calling thread until a proxy is created (or the timeout is reached), any number of
	 * threads may call {@code getProxy()} simultaneously.
	 * 
	 * @throws MatlabConnectionException
	 * @return proxy
	 */
	public MatlabProxy getProxy() throws MatlabConnectionException;

	/**
	 * Requests a {@link MatlabProxy}. When the proxy has been created it will be provided to the {@code callback}. The
	 * proxy may be provided to the callback before this method returns. There is no timeout. The returned
	 * {@link Request} instance provides information about the request and can be used to cancel the request.
	 * <br><br>
	 * This method is non-blocking. Any number of requests may be made simultaneously from the same thread or different
	 * threads.
	 * 
	 * @throws MatlabConnectionException
	 * @return request
	 */
	public Request requestProxy(RequestCallback callback) throws MatlabConnectionException;
}


<|start_filename|>src/matlabcontrol/link/UnassignableReturnException.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * The type to be returned is not assignable to the return type. This exception is conceptually similar to a
 * {@link ClassCastException} except that it is thrown before the cast would ever occur. For primitive return types,
 * this is similar to a {@link NullPointerException} being thrown when the return value is {@code null} and therefore
 * cannot be un-boxed.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class UnassignableReturnException extends RuntimeException {
	private static final long serialVersionUID = 0xE500L;

	UnassignableReturnException(String msg) {
		super(msg);
	}
}


<|start_filename|>src/matlabcontrol/MatlabConnectionException.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

/**
 * Represents a failure to connect to MATLAB or make MATLAB available for a connection.
 * 
 * @since 2.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class MatlabConnectionException extends Exception {
	private static final long serialVersionUID = 0xA400L;

	MatlabConnectionException(String msg) {
		super(msg);
	}

	MatlabConnectionException(String msg, Throwable cause) {
		super(msg, cause);
	}
}


<|start_filename|>src/matlabcontrol/link/MatlabNumericMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
abstract class MatlabNumericMatrix<L, T> extends MatlabMatrix<L, T> {
	/**
	 * Returns {@code true} if the array has no imaginary values, {@code false} otherwise. Equivalent to the MATLAB
	 * {@code isreal} function.
	 * 
	 * @return 
	 */
	public boolean isReal() {
		return getBaseArray().isReal();
	}

	/**
	 * Returns an array that holds the real values from the MATLAB array. Each call returns a new copy which may be used
	 * in any manner; modifications to it will have no effect on this instance.
	 * 
	 * @return real array
	 */
	public T toRealArray() {
		return getBaseArray().toRealArray();
	}

	/**
	 * Returns an array that holds the imaginary values from the MATLAB array. Each call returns a new copy which may be
	 * used in any manner; modifications to it will have no effect on this instance. If this array is real then the
	 * returned array will be have {@code 0} as all of its base elements.
	 * 
	 * @return imaginary array
	 */
	public T toImaginaryArray() {
		return getBaseArray().toImaginaryArray();
	}

	/**
	 * Gets the element at {@code index} treating this array as a MATLAB column vector. This is equivalent to indexing
	 * into a MATLAB array with just one subscript.
	 * 
	 * @param index
	 * @return element at {@code index}
	 * @throws ArrayIndexOutOfBoundsException if {@code index} is out of bounds
	 */
	public abstract MatlabNumber<?> getElementAtLinearIndex(int index);

	public abstract MatlabNumber<?> getElementAtIndices(int row, int column);

	public abstract MatlabNumber<?> getElementAtIndices(int row, int column, int page);

	/**
	 * Gets the element at the specified {@code row}, {@code column}, and {@code pages}.
	 * 
	 * @param row
	 * @param column
	 * @param pages
	 * @return element at {@code row}, {@code column}, and {@code pages}
	 * @throws IllegalArgumentException if number of indices does not equal this array's number of dimensions
	 * @throws ArrayIndexOutOfBoundsException if the indices are out of bound
	 */
	public abstract MatlabNumber<?> getElementAtIndices(int row, int column, int... pages);
}


<|start_filename|>src/matlabcontrol/link/MatlabLogicalFullMatrix.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 *
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class MatlabLogicalFullMatrix<T> extends MatlabLogicalMatrix<T> {
	private final FullArray<boolean[], T> _array;

	MatlabLogicalFullMatrix(boolean[] values, int[] dimensions) {
		_array = new FullArray<boolean[], T>(boolean[].class, values, null, dimensions);
	}

	MatlabLogicalFullMatrix(T values) {
		_array = new FullArray<boolean[], T>(boolean[].class, values, null);
	}

	@Override
	BaseArray<boolean[], T> getBaseArray() {
		return _array;
	}

	@Override
	public boolean getElementAtLinearIndex(int linearIndex) {
		return _array._real[linearIndex];
	}

	@Override
	public boolean getElementAtIndices(int row, int column) {
		return _array._real[_array.getLinearIndex(row, column)];
	}

	@Override
	public boolean getElementAtIndices(int row, int column, int page) {
		return _array._real[_array.getLinearIndex(row, column, page)];
	}

	@Override
	public boolean getElementAtIndices(int row, int column, int[] pages) {
		return _array._real[_array.getLinearIndex(row, column, pages)];
	}
}


<|start_filename|>src/matlabcontrol/MatlabProxyFactory.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import matlabcontrol.MatlabProxy.Identifier;

/**
 * Creates instances of {@link MatlabProxy}. Any number of proxies may be created with a factory.
 * <br><br>
 * How the proxies will connect to a session of MATLAB depends on whether the factory is running inside or outside
 * MATLAB:
 * <br><br>
 * <i>Running inside MATLAB</i><br>
 * The proxy will connect to the session of MATLAB this factory is running in.
 * <br><br>
 * <i>Running outside MATLAB</i><br>
 * By default a new session of MATLAB will be started and connected to, but the factory may be configured via the
 * options provided to this factory to connect to a previously controlled session.
 * <br><br>
 * This class is unconditionally thread-safe. Any number of proxies may be created simultaneously.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class MatlabProxyFactory implements ProxyFactory {
	private final ProxyFactory _delegateFactory;

	/**
	 * Constructs the factory using default options.
	 * 
	 * @throws MatlabConnectionException 
	 */
	public MatlabProxyFactory() {
		this(new MatlabProxyFactoryOptions.Builder().build());
	}

	/**
	 * Constructs the factory with the specified {@code options}. Depending on the whether the factory is running inside
	 * MATLAB or outside MATLAB will determine if a given option is used.
	 * 
	 * @param options
	 */
	public MatlabProxyFactory(MatlabProxyFactoryOptions options) {
		if (Configuration.isRunningInsideMatlab()) {
			_delegateFactory = new LocalMatlabProxyFactory(options);
		} else {
			_delegateFactory = new RemoteMatlabProxyFactory(options);
		}
	}

	@Override
	public MatlabProxy getProxy() throws MatlabConnectionException {
		return _delegateFactory.getProxy();
	}

	@Override
	public Request requestProxy(RequestCallback callback) throws MatlabConnectionException {
		if (callback == null) {
			throw new NullPointerException("The request callback may not be null");
		}

		return _delegateFactory.requestProxy(callback);
	}

	/**
	 * Provides the requested proxy.
	 * 
	 * @since 4.0.0
	 * @author <a href="mailto:<EMAIL>"><NAME></a>
	 */
	public static interface RequestCallback {
		/**
		 * Called when the proxy has been created. Because requests have no timeout, there is no guarantee that this
		 * method will ever be called.
		 * 
		 * @param proxy 
		 */
		public void proxyCreated(MatlabProxy proxy);
	}

	/**
	 * A request for a proxy. Because requests have no timeout, a {@code Request} has no concept of
	 * failure.
	 * <br><br>
	 * Implementations of this class are unconditionally thread-safe.
	 * <br><br>
	 * <b>WARNING:</b> This interface is not intended to be implemented by users of matlabcontrol. Methods may be added
	 * to this interface, and these additions will not be considered breaking binary compatibility.
	 * 
	 * @since 4.0.0
	 * @author <a href="mailto:<EMAIL>"><NAME></a>
	 */
	public static interface Request {
		/**
		 * The identifier of the proxy associated with this request. If the proxy is created, then its identifier
		 * accessible via {@link MatlabProxy#getIdentifier()} will return {@code true} when tested for equivalence with
		 * the identifier returned by this method using {@link Identifier#equals(java.lang.Object)}.
		 * 
		 * @return proxy's identifier
		 */
		public Identifier getProxyIdentifer();

		/**
		 * Attempts to cancel the request. If the request has already been completed or cannot successfully be canceled
		 * then {@code false} will be returned, otherwise {@code true} will be returned. If the request has already been
		 * successfully canceled then this method will have no effect and {@code true} will be returned.
		 * 
		 * @return if successfully cancelled
		 */
		public boolean cancel();

		/**
		 * If the request has been successfully cancelled.
		 * 
		 * @return if successfully cancelled
		 */
		public boolean isCancelled();

		/**
		 * Returns {@code true} if the proxy has been created.
		 * 
		 * @return if the proxy has been created
		 */
		public boolean isCompleted();
	}

	/**
	 * A callback interface for receiving the commands which must be
	 * copy-pasted into MATLAB to initiate a connection.
	 */
	public interface CopyPasteCallback {
		/**
		 * The given code should be copy-pasted into MATLAB.
		 */
		void copyPaste(String matlabCmdsToConnect);
	}
}


<|start_filename|>src/matlabcontrol/package-info.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2015, DiffPlug
 */
package matlabcontrol;


<|start_filename|>src/matlabcontrol/link/LinkingException.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol.link;

/**
 * Issue linking a Java method to a MATLAB function.
 * 
 * @since 4.2.0
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class LinkingException extends RuntimeException {
	private static final long serialVersionUID = 0xD500L;

	LinkingException(String msg) {
		super(msg);
	}

	LinkingException(String msg, Throwable cause) {
		super(msg, cause);
	}
}


<|start_filename|>src/matlabcontrol/LocalMatlabProxyFactory.java<|end_filename|>
/*
 * Code licensed under new-style BSD (see LICENSE).
 * All code up to tags/original: Copyright (c) 2013, <NAME>
 * All code after tags/original: Copyright (c) 2016, DiffPlug
 */
package matlabcontrol;

import java.util.concurrent.atomic.AtomicInteger;

import matlabcontrol.MatlabProxy.Identifier;
import matlabcontrol.MatlabProxyFactory.Request;
import matlabcontrol.MatlabProxyFactory.RequestCallback;

/**
 * Creates local instances of {@link MatlabProxy}.
 * 
 * @since 4.0.0
 * 
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
class LocalMatlabProxyFactory implements ProxyFactory {
	public LocalMatlabProxyFactory(MatlabProxyFactoryOptions options) {}

	@Override
	public LocalMatlabProxy getProxy() throws MatlabConnectionException {
		JMIValidator.validateJMIMethods();

		return new LocalMatlabProxy(new LocalIdentifier());
	}

	@Override
	public Request requestProxy(RequestCallback requestCallback) throws MatlabConnectionException {
		LocalMatlabProxy proxy = getProxy();
		requestCallback.proxyCreated(proxy);

		return new LocalRequest(proxy.getIdentifier());
	}

	private static final class LocalIdentifier implements Identifier {
		private static final AtomicInteger PROXY_CREATION_COUNTER = new AtomicInteger();

		private final int _id = PROXY_CREATION_COUNTER.getAndIncrement();

		@Override
		public boolean equals(Object other) {
			boolean equals;

			if (other instanceof LocalIdentifier) {
				equals = (((LocalIdentifier) other)._id == _id);
			} else {
				equals = false;
			}

			return equals;
		}

		@Override
		public int hashCode() {
			return _id;
		}

		@Override
		public String toString() {
			return "PROXY_LOCAL_" + _id;
		}
	}

	private static final class LocalRequest implements Request {
		private final Identifier _proxyID;

		private LocalRequest(Identifier proxyID) {
			_proxyID = proxyID;
		}

		@Override
		public Identifier getProxyIdentifer() {
			return _proxyID;
		}

		@Override
		public boolean cancel() {
			return false;
		}

		@Override
		public boolean isCancelled() {
			return false;
		}

		@Override
		public boolean isCompleted() {
			return true;
		}
	}
}
