All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.n52.matlab.control.MatlabProxy Maven / Gradle / Ivy

The newest version!
package org.n52.matlab.control;

/*
 * Copyright (c) 2013, Joshua Kaplan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *  - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 *    disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other materials provided with the distribution.
 *  - Neither the name of matlabcontrol nor the names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Communicates with a running MATLAB session. This class cannot be instantiated, it may be created with a
 * {@link MatlabProxyFactory}. Interaction with MATLAB occurs as if calling {@code eval} and {@code feval} in the
 * MATLAB Command Window.
 * 

Communicating with MATLAB

* Methods which interact with MATLAB provide Java objects to the MATLAB environment and retrieve data from the MATLAB * environment as Java objects. The following description of how the conversion between MATLAB and Java types occurs is * based on tests conducted on versions of MATLAB R2007b through R2010b. Unless otherwise noted the behavior was * identical on all tested versions. However, this behavior is not officially documented by The MathWorks and may change * for future versions of MATLAB. (matlabcontrol is not compatible with versions prior to MATLAB R2007b.) *

* MATLAB to Java
*
Numeric Classes and Logical Class
* All MATLAB numeric types whether they are a singular value or an array/matrix (of any dimension) are always converted * into a one-dimensional Java {@code double[]}. For complex numbers, only the real component is converted. MATLAB * {@code logical}s whether a singular value or an array/matrix (of any dimension) are always converted into a * one-dimensional Java {@code boolean[]}. MATLAB arrays are stored in a linear manner, which has been * documented by The MathWorks. It is in * this linear manner that MATLAB arrays are returned to Java. (Sparse matrices are stored differently and are not sent * to Java in an easy to use manner.) *

Character Class
* MATLAB {@code char} singular values are returned as a Java {@code String}. One-dimensional MATLAB {@code char} * arrays are returned as a Java {@code String}. Two-dimensional MATLAB {@code char} arrays are returned as a Java * {@code String[]} with each row of the MATLAB array becoming a Java {@code String}. MATLAB {@code char} arrays of * more than two dimensions have an inconsistent conversion to a Java type, although all observed conversions are * either a Java {@code String} or an array of {@code String}s. *

Cell and Struct Arrays
* MATLAB {@code cell} arrays and {@code struct} arrays are converted to a Java {@code Object[]}, often with arrays * inside of them. *

Function Handles and Non-Built-In Classes
* MATLAB {@code function_handle}s and all non-built-in classes (such as the {@code Map} class or user defined classes) * are converted to an instance of {@code com.mathworks.jmi.types.MLArrayRef} that is not {@code Serializable} which * prevents it from being transferred to a Java application running outside MATLAB (more information on this can be * found in the exception section below). *

* Java to MATLAB
*
Primitives
* It is not possible to directly send a Java primitive to the MATLAB environment because all methods which interact * with MATLAB take in either {@code Object} or {@code Object[]} which results in the Java primitives becoming their * auto-boxed class equivalent. (For example {@code int} becomes {@code Integer}.) Java primitive arrays, such as * {@code int[]} are {@code Object}s and can therefore be sent to the MATLAB environment. They are converted as follows: *

*
* * * * * * * * * * *
Java Type MATLAB Type
boolean[] logical array
char[] not supported*
byte[] int8 array
short[] int16 array
int[] int32 array
long[] not supported*
float[] single array
double[] double array
*
*
* *In MATLAB R2009b and higher, MATLAB will throw an exception. In MATLAB R2008b and earlier, MATLAB will segfault. The * behavior in MATLAB R2009a is not known. *

{@code Number}s
* Subclasses of {@link Number}, which includes all of the auto-boxed versions of Java primitive numeric types, become * MATLAB {@code double}s. *

{@code Boolean}s
* {@link Boolean}s are converted to MATLAB {@code logical}s. *

{@code Character}s
* {@link Character}s are converted to MATLAB {@code char}s. *

{@code String}s
* {@link String}s are converted to MATLAB {@code char} arrays. *

Object Arrays
* Arrays of non-primitive types are converted to MATLAB {@code cell} arrays. The contents of the array are converted * according to these same rules. Note that Java's multidimensional arrays are not an exception to this rule. For * instance a {@code double[][]} is an array of {@code double[]}s and so MATLAB will create a cell array of MATLAB * {@code double} arrays. *

Other Classes
* Classes not otherwise mentioned remain as their original Java type. Objects contained within that class or instances * of that class are not automatically converted by MATLAB, although when fields or methods are accessed in the MATLAB * environment they may be converted into MATLAB types as * documented by The MathWorks. *

* Behavior of transferred data
* How Java objects sent to MATLAB or retrieved from MATLAB behave depends on several factors: *

* Running outside MATLAB
* References to Java objects are copies. (There is one exception to this rule. Objects that are {@link java.rmi.Remote} * will act as if they are not copies. This is because matlabcontrol communicates with MATLAB's Java Virtual Machine * using * Remote Method Invocation.) *

* Running inside MATLAB
* References to Java objects in MATLAB that are returned to Java, reference the same object. When passing a reference * to a Java object to MATLAB, if the Java object is not converted to a MATLAB type then it will reference the same * object in the MATLAB environment. *

* Help transferring data
* The {@link matlabcontrol.extensions.MatlabProxyLogger} exists to record what is being returned from MATLAB. * The {@link matlabcontrol.extensions.MatlabTypeConverter} can convert between complicated Java and MATLAB types. * Currently only MATLAB numeric arrays are supported. *

Exceptions

* Proxy methods that are relayed to MATLAB can throw {@link MatlabInvocationException}s. They will be thrown if: *
    *
  • The proxy has been disconnected via {@link #disconnect()}.
  • *
  • Attempting to do anything that would normally cause an error in MATLAB such as calling a function improperly or * referencing a variable that does not exist.
  • *
  • The underlying Java MATLAB Interface (JMI) API does not support the operation. For instance, attempting to send * a {@code long[]} to MATLAB. Due to the undocumented nature of this interface, it is not entirely known what * actions may result in an exception.
  • *
    Running outside MATLAB *
  • Communication between this Java Virtual Machine and the one that MATLAB is running in is disrupted, most * commonly due to closing MATLAB.
  • *
  • The class of an object to be sent or returned is not {@link java.io.Serializable} or * {@link java.rmi.Remote}.1 Java primitives and arrays behave as if they were {@code Serializable}.
  • *
  • The class of an object to be returned from MATLAB is not defined in your application and no * {@link SecurityManager} has been installed.2
  • *
  • The class of an object to sent to MATLAB is not defined in MATLAB and the class is not on your application's * classpath.3
  • *
* 1This is a requirement of Remote Method Invocation, which matlabcontrol uses when running outside MATLAB. *

* 2 This is due to Remote Method Invocation prohibiting loading classes defined in remote Java Virtual * Machines unless a {@code SecurityManager} has been set. {@link PermissiveSecurityManager} exists to provide an easy * way to set a security manager without further restricting permissions. Please consult * {@code PermissiveSecurityManager}'s documentation for more information. *

* 3 MATLAB sessions started by a {@code MatlabProxyFactory} are able to load all classes defined in your * application's class path as specified by the {@code java.class.path} property. Some frameworks load classes without * placing them on the class path, in that case matlabcontrol will not know about them and cannot tell MATLAB how to * load them. *

Thread Safety

* This proxy is unconditionally thread-safe. Methods which interact with MATLAB may be called concurrently; however * they will be completed sequentially on MATLAB's main thread. Calls to MATLAB from a given thread will be executed in * the order they were invoked. No guarantees are made about the relative ordering of calls made from different threads. * This proxy may not be the only thing interacting with MATLAB's main thread. One proxy running outside MATLAB and any * number of proxies running inside MATLAB may be simultaneously connected. If MATLAB is not hidden from user * interaction then a user may also be making use of MATLAB's main thread. This means that two sequential calls to the * proxy from the same thread that interact with MATLAB will execute in that order, but interactions with MATLAB may * occur between the two calls. In typical use it is unlikely this behavior will pose a problem. However, for some uses * cases it may be necessary to guarantee that several interactions with MATLAB occur without interruption. * Uninterrupted access to MATLAB's main thread may be obtained by use of * {@link #invokeAndWait(MatlabProxy.MatlabThreadCallable) invokeAndWait(...)}. *

Threads

* When running outside MATLAB, the proxy makes use of multiple internally managed threads. When the proxy * becomes disconnected from MATLAB it notifies its disconnection listeners and then terminates all threads it was using * internally. A proxy may disconnect from MATLAB without exiting MATLAB by calling {@link #disconnect()}. * * @see MatlabProxyFactory#getProxy() * @see MatlabProxyFactory#requestProxy(matlabcontrol.MatlabProxyFactory.RequestCallback) * @since 4.0.0 * @author Joshua Kaplan */ public abstract class MatlabProxy implements MatlabOperations { /** * Unique identifier for this proxy. */ private final Identifier _id; /** * Whether the session of MATLAB this proxy is connected to is an existing session. */ private final boolean _existingSession; /** * Listeners for disconnection. */ private final CopyOnWriteArrayList _listeners; /** * This constructor is package private to prevent subclasses from outside of this package. */ MatlabProxy(Identifier id, boolean existingSession) { _id = id; _existingSession = existingSession; _listeners = new CopyOnWriteArrayList(); } /** * Returns the unique identifier for this proxy. * * @return identifier */ public Identifier getIdentifier() { return _id; } /** * Whether this proxy is connected to a session of MATLAB that was running previous to the request to create this * proxy. * * @return if existing session */ public boolean isExistingSession() { return _existingSession; } /** * Returns a brief description of this proxy. The exact details of this representation are unspecified and are * subject to change. * * @return */ @Override public String toString() { return "[" + this.getClass().getName() + " identifier=" + this.getIdentifier() + "," + " connected=" + this.isConnected() + "," + " insideMatlab=" + this.isRunningInsideMatlab() + "," + " existingSession=" + this.isExistingSession() + "]"; } /** * Adds a disconnection listener that will be notified when this proxy becomes disconnected from MATLAB. * * @param listener */ public void addDisconnectionListener(DisconnectionListener listener) { _listeners.add(listener); } /** * Removes a disconnection listener. It will no longer be notified. * * @param listener */ public void removeDisconnectionListener(DisconnectionListener listener) { _listeners.remove(listener); } /** * Notifies the disconnection listeners this proxy has become disconnected. */ void notifyDisconnectionListeners() { for(DisconnectionListener listener : _listeners) { listener.proxyDisconnected(this); } } /** * Whether this proxy is running inside of MATLAB. * * @return */ public abstract boolean isRunningInsideMatlab(); /** * Whether this proxy is connected to MATLAB. *

* The most likely reasons for this method to return {@code false} are if the proxy has been disconnected via * {@link #disconnect()} or MATLAB has been closed (when running outside MATLAB). * * @return if connected * * @see #disconnect() * @see #exit() */ public abstract boolean isConnected(); /** * Disconnects the proxy from MATLAB. MATLAB will not exit. After disconnecting, any method sent to MATLAB will * throw an exception. A proxy cannot be reconnected. Returns {@code true} if the proxy is now disconnected, * {@code false} otherwise. * * @return if disconnected * * @see #exit() * @see #isConnected() */ public abstract boolean disconnect(); /** * Exits MATLAB. Attempting to exit MATLAB with either a {@code eval} or {@code feval} command will cause MATLAB to * hang indefinitely. * * @throws MatlabInvocationException * * @see #disconnect() * @see #isConnected() */ public abstract void exit() throws MatlabInvocationException; /** * Runs the {@code callable} on MATLAB's main thread and waits for it to return its result. This method allows for * uninterrupted access to MATLAB's main thread between two or more interactions with MATLAB. *

* If running outside MATLAB the {@code callable} must be {@link java.io.Serializable}; it may not be * {@link java.rmi.Remote}. * * @param * @param callable * @return result of the callable * @throws MatlabInvocationException */ public abstract T invokeAndWait(MatlabThreadCallable callable) throws MatlabInvocationException; /** * Uninterrupted block of computation performed in MATLAB. * * @see MatlabProxy#invokeAndWait(matlabcontrol.MatlabProxy.MatlabThreadCallable) * @param type of the data returned by the callable */ public static interface MatlabThreadCallable { /** * Performs the computation in MATLAB. The {@code proxy} provided will invoke its methods directly on MATLAB's * main thread without delay. This {@code proxy} should be used to interact with MATLAB, not a * {@code MatlabProxy} (or any class delegating to it). * * @param proxy * @return result of the computation * @throws MatlabInvocationException */ public T call(MatlabThreadProxy proxy) throws MatlabInvocationException; } /** * Operates on MATLAB's main thread without interruption. Currently this interface has only the methods defined in * {@link MatlabOperations}, but this may change in future releases. *

* An implementation of this interface is provided to * {@link MatlabThreadCallable#call(MatlabProxy.MatlabThreadProxy)} so that the callable can interact with * MATLAB. Implementations of this interface behave identically to a {@link MatlabProxy} running inside of MATLAB * except that they are not thread-safe. They must be used solely on the thread that calls * {@link MatlabThreadCallable#call(MatlabProxy.MatlabThreadProxy) call(...)}. *

* WARNING: 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. */ public static interface MatlabThreadProxy extends MatlabOperations { } /** * Listens for a proxy's disconnection from MATLAB. * * @see MatlabProxy#addDisconnectionListener(matlabcontrol.MatlabProxy.DisconnectionListener) * @see MatlabProxy#removeDisconnectionListener(matlabcontrol.MatlabProxy.DisconnectionListener) * @since 4.0.0 * @author Joshua Kaplan */ public static interface DisconnectionListener { /** * Called when the proxy becomes disconnected from MATLAB. The proxy passed in will always be the proxy that * the listener was added to. The proxy is provided so that if desired a single implementation of this * interface may easily be used for multiple proxies. * * @param proxy disconnected proxy */ public void proxyDisconnected(MatlabProxy proxy); } /** * Uniquely identifies a proxy. *

* Implementations of this interface are unconditionally thread-safe. *

* WARNING: 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 Joshua Kaplan */ public static interface Identifier { /** * Returns {@code true} if {@code other} is equal to this identifier, {@code false} otherwise. * * @param other * @return */ @Override public boolean equals(Object other); /** * Returns a hash code which conforms to the {@code hashCode} contract defined in {@link Object#hashCode()}. * * @return */ @Override public int hashCode(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy