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

ca.weblite.objc.Proxy Maven / Gradle / Ivy

There is a newer version: 1.2
Show newest version
package ca.weblite.objc;

import static ca.weblite.objc.RuntimeUtils.*;
import com.sun.jna.Pointer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * A wrapper around a native (Objective-C) object that allows for sending
 * messages from Java.
 *
 * 

Example Wrapping NSMutableArray Object

* *

The following snippet is taken from a unit test, to give you an idea * of how to use the Proxy class to wrap an Objective-C object.

* * * *

The NSRange object is a structure that we define in Java to correspond * with the NSRange objective-c structure according to JNA conventions. It's * implementation (for your reference) was:

* * * @see JavaNativeAccess On GitHub * @author shannah * @version $Id: $Id * @since 1.1 */ public class Proxy implements Peerable { /** * A cache of Proxy objects that is used by the load() method to ensure * that we don't create different Proxy objects for the same Objective-C * native pointer. */ private static final Map proxyCache = new HashMap<>(); /** * The client that is used to make requests to the Objective-C runtime. */ Client client; /** * The Objective-C object to which this proxy sends its messages. */ Pointer peer; private int retainCount = 0; /** * Retains the Proxy object in the Cache. This is not related to the * Objective-C message "release". It pertains only to the Java cache * of proxy objects. * * @param obj The object that is being retained. If the object is a Proxy * object, then its retainCount will be incremented. * @return The object that was passed to it. */ public static Object retain(Object obj){ synchronized(proxyCache){ if (obj instanceof Proxy) { Proxy pobj = (Proxy)obj; pobj.retainCount++; } } return obj; } /** * Releases the Proxy object from the Cache. This is not related to the * Objective-C message "release". It pertains only to the Java cache * of proxy objects. * * @param obj The object that is being released. If the object is a Proxy * object, then its retainCount will be decremented, and, if it is zero, * will be removed from the proxy cache. * @return The object that was passed to it. */ public static Object release(Object obj){ synchronized (proxyCache){ if (obj instanceof Proxy) { Proxy pobj = (Proxy)obj; pobj.retainCount--; if ( pobj.retainCount <= 0 ){ proxyCache.remove(pobj.getPeer()); } } } return obj; } /** *

drainCache.

*/ public static void drainCache(){ synchronized(proxyCache){ Set remove = new HashSet(); for ( Proxy p : proxyCache.values() ){ if ( p.retainCount == 0 ){ remove.add(p); } } for ( Proxy p : remove ){ proxyCache.remove(p.getPeer()); } } } /** * Creates a proxy for a Null pointer. */ public Proxy(){ this(Client.getInstance()); } /** * Creates a proxy for a Null pointer using the specified Client object. * * @param client a {@link ca.weblite.objc.Client} object. */ public Proxy(Client client){ this(client, Pointer.NULL); } /** * Creates a proxy for the specified peer Objective-C object, using * the specified client to send messages to the peer. * * @param client a {@link ca.weblite.objc.Client} object. * @param peer a {@link com.sun.jna.Pointer} object. */ public Proxy(Client client, Pointer peer){ this.client = client; this.peer = peer; } /** * Creates a proxy for the specified peer Objective-C object. * * @param peer a {@link com.sun.jna.Pointer} object. */ public Proxy(Pointer peer){ this(Client.getInstance(), peer); } /** * Loads a proxy object for the specified pointer to an objective-c object. * If a Proxy has previously been created for this pointer, this same * proxy object will be loaded from the cache. * *

Note: This will perform a retain() on the Proxy object, so you should * release it when you are done with it to remove it from the cache.

* * @param peer The objective-c peer object. * @return A proxy that wraps the provided peer object. */ public static Proxy load(Pointer peer){ synchronized (proxyCache){ Proxy cached = proxyCache.get(peer); if ( cached == null ){ cached = new Proxy(peer); proxyCache.put(peer, cached); } retain(cached); return cached; } } /** * Removes the proxy from the proxy cache, and optionally sends a dealloc message * to the peer. * * @param sendDeallocMessage IF true, then this will also send a dealloc message * to the peer. If false, then it will simply remove from the Proxy cache, but * leave the Objective-C object intact. */ public void dispose(boolean sendDeallocMessage){ synchronized(proxyCache) { proxyCache.remove(getPeer()); if ( sendDeallocMessage ){ send("dealloc"); } } } /** * A wrapper for the send() method, that returns a Pointer. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a Pointer. */ public Pointer sendPointer(Pointer selector, Object... args){ return (Pointer)send(selector, args); } /** * A wrapper for the send() method, that returns a Pointer. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a Pointer. */ public Pointer sendPointer(String selector, Object... args){ return sendPointer(sel(selector), args); } /** * A wrapper for the send() method, that returns a Pointer. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a Pointer. */ public Proxy sendProxy(String selector, Object... args){ return (Proxy)send(selector, args); } /** * A wrapper for the send() method, that returns a Pointer. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a Pointer. */ public Proxy sendProxy(Pointer selector, Object... args){ return (Proxy)send(selector, args); } /** *

sendString.

* * @param selector a {@link com.sun.jna.Pointer} object. * @param args a {@link java.lang.Object} object. * @return a {@link java.lang.String} object. */ public String sendString(Pointer selector, Object... args){ return (String)send(selector, args); } /** *

sendString.

* * @param selector a {@link java.lang.String} object. * @param args a {@link java.lang.Object} object. * @return a {@link java.lang.String} object. */ public String sendString(String selector, Object... args){ return sendString(sel(selector), args); } /** * A wrapper for the send() method, that returns an int. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as an int. */ public int sendInt(Pointer selector, Object... args){ Object res = send(selector, args); if (res instanceof Boolean) { return ((Boolean)res) ? 1 : 0; } else if (res instanceof Byte) { return (Byte) res; } else if (res instanceof Integer){ return (Integer) res; } else if (res instanceof Long){ return ((Long) res).intValue(); } else { // TODO Use custom exception class throw new RuntimeException("Result not convertible to int: " + res); } } /** * A wrapper for the send() method, that returns an int. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as an int. */ public int sendInt(String selector, Object... args){ return sendInt(sel(selector), args); } /** * A wrapper for the send() method, that returns a double. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a double. */ public double sendDouble(Pointer selector, Object... args){ return (Double)send(selector, args); } /** * A wrapper for the send() method, that returns a double. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a double. */ public double sendDouble(String selector, Object... args){ return sendDouble(sel(selector), args); } /** * A wrapper for the send() method, that returns a boolean. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a boolean. */ public boolean sendBoolean(Pointer selector, Object... args){ Object res = send(selector, args); if (res instanceof Boolean) { return (Boolean) res; } else if (res instanceof Byte) { byte bres = (Byte) res; return bres > 0; } else if (res instanceof Integer){ int ires = (Integer) res; return ires > 0; } else if (res instanceof Long) { long lres = (Long) res; return lres > 0L; } else { // TODO Use custom exception class throw new RuntimeException("Result not convertible to boolean: " + res); } } /** * A wrapper for the send() method, that returns a boolean. * * @param selector The selector to call on the peer. * @param args Variable argument list. * @return The result of the message call as a boolean. */ public boolean sendBoolean(String selector, Object... args){ return sendBoolean(sel(selector), args); } /** * Sends a message to the peer. * * @param selector The selector to send to. * @param args Variable argument list. * @return The result of the message call. */ public Object send(Pointer selector, Object... args){ return client.send(peer, selector, args); } /** * Sends a message to the peer. * * @param selector The selector to send to. * @param args Variable argument list. * @return The result of the message call. */ public Object send(String selector, Object... args){ return client.send(peer, selector, args); } /** * Sends a message to the peer. * * @return The result of the message call. * @param msgs a {@link ca.weblite.objc.Message} object. */ public Object send(Message... msgs){ return client.send(msgs); } /** * Sends a message to the peer. * * @param selector The selector to send to. * @param args Variable argument list. * @return The result of the message call. */ public Object sendRaw(Pointer selector, Object... args){ return Client.getRawClient().send(this, selector, args); } /** * Sends a message to the peer without performing any type coercion to * the inputs or outputs. * * @param selector The selector to send to. * @param args Variable argument list. * @return The result of the message call. */ public Object sendRaw(String selector, Object... args){ return sendRaw(RuntimeUtils.sel(selector), args); } /** * Sends a message to the peer without performing any type coercion to * the inputs or outputs. * * @return The result of the message call. * @param msgs a {@link ca.weblite.objc.Message} object. */ public Object sendRaw(Message... msgs){ return Client.getRawClient().send(msgs); } /** *

chain.

* * @param selector a {@link com.sun.jna.Pointer} object. * @param args a {@link java.lang.Object} object. * @return a {@link ca.weblite.objc.Proxy} object. */ public Proxy chain(Pointer selector, Object... args){ send(selector, args); return this; } /** *

chain.

* * @param selector a {@link java.lang.String} object. * @param args a {@link java.lang.Object} object. * @return a {@link ca.weblite.objc.Proxy} object. */ public Proxy chain(String selector, Object... args){ send(selector, args); return this; } /** *

chain.

* * @param msgs a {@link ca.weblite.objc.Message} object. * @return a {@link ca.weblite.objc.Proxy} object. */ public Proxy chain(Message... msgs){ send(msgs); return this; } /** * Returns the client that is used by this Proxy object. * * @return a {@link ca.weblite.objc.Client} object. */ public Client getClient(){ return client; } /** * Sets the client that should be used for sending messages to the * peer object. * * @param client a {@link ca.weblite.objc.Client} object. * @return a {@link ca.weblite.objc.Proxy} object. */ public Proxy setClient(Client client){ this.client = client; return this; } /** * {@inheritDoc} * * Returns the Pointer to the native peer object. */ @Override public Pointer getPeer(){ return peer; } /** * {@inheritDoc} * * Sets the pointer to the native peer object. */ @Override public void setPeer(Pointer peer){ this.peer = peer; } /** * {@inheritDoc} * * Outputs the object as a string. This is a wrapper around the "description" * method of NSObject. */ @Override public String toString(){ if ( getPeer() == null ){ return "null"; } Pointer res = Client.getRawClient().sendPointer(getPeer(), "description"); //System.out.println("About to send UTF8String msg"); Pointer str = Client.getRawClient().sendPointer(res, "UTF8String"); //System.out.println("Sent UTF8String msg"); return str.getString(0); } /** * {@inheritDoc} * * Compares this object to another Peerable object. This effectively says * that the objects are equal if their peer objects are equal. */ @Override public boolean equals(Object o){ if (o == this) { return true; } else if (!(o instanceof Peerable)) { return false; } Peerable p = (Peerable)o; return (getPeer() == p.getPeer()); } @Override public int hashCode(){ return getPeer().hashCode(); } /** * Wrapper for Key-Value coding. I.e. a wrapper for the setValue:forKey: * message of NSObject. * * @param key a {@link java.lang.String} object. * @param value a {@link java.lang.Object} object. */ public void set(String key, Object value){ send("setValue:forKey:", value, key); } /** * Wrapper for key-value coding. I.e a wrapper for the valueForKey: method * of NSObject. * * @param key a {@link java.lang.String} object. * @return a {@link java.lang.Object} object. */ public Object get(String key){ return send("valueForKey:", key); } /** * Returns the KVC coded value for the specified key as an int. * * @param key a {@link java.lang.String} object. * @return a int. */ public int getInt(String key){ return sendInt("valueForKey:", key); } /** * Returns the KVC coded value for the specified key as a boolean. * * @param key a {@link java.lang.String} object. * @return a boolean. */ public boolean getBoolean(String key){ return sendBoolean("valueForKey:", key); } /** * Returns the KVC coded value for the specified key as a Proxy. * * @param key a {@link java.lang.String} object. * @return a {@link ca.weblite.objc.Proxy} object. */ public Proxy getProxy(String key){ return sendProxy("valueForKey:", key); } /** * Returns the KVC coded value for the specified key as a double. * * @param key a {@link java.lang.String} object. * @return a double. */ public double getDouble(String key){ return sendDouble("valueForKey:", key); } /** * Returns the KVC coded value for the specified key as a Pointer. * * @param key a {@link java.lang.String} object. * @return a {@link com.sun.jna.Pointer} object. */ public Pointer getPointer(String key){ return sendPointer("valueForKey:", key); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy