001/*******************************************************************************
002 * Copyright (c) 2000, 2007 IBM Corporation and others.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the Eclipse Public License v1.0
005 * which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v10.html
007 *
008 * Contributors:
009 *     IBM Corporation - initial API and implementation
010 *******************************************************************************/
011package org.fusesource.hawtjni.runtime;
012
013/**
014 * Instances of this class represent entry points into Java which can be invoked
015 * from operating system level callback routines.
016 * <p>
017 * IMPORTANT: A callback is only valid when invoked on the thread which created
018 * it. The results are undefined (and typically bad) when a callback is passed
019 * out to the operating system (or other code) in such a way that the callback
020 * is called from a different thread.
021 */
022
023public class Callback {
024
025    Object object;
026
027    String method, signature;
028
029    int argCount;
030
031    long /* int */ address, errorResult;
032
033    boolean isStatic, isArrayBased;
034
035    static final String PTR_SIGNATURE = "J"; /* C.PTR_SIZEOF == 4 ? "I" : "J"; */
036
037    static final String SIGNATURE_0 = getSignature(0);
038    static final String SIGNATURE_1 = getSignature(1);
039    static final String SIGNATURE_2 = getSignature(2);
040    static final String SIGNATURE_3 = getSignature(3);
041    static final String SIGNATURE_4 = getSignature(4);
042
043    static final String SIGNATURE_N = "([" + PTR_SIGNATURE + ")" + PTR_SIGNATURE; 
044
045    /**
046     * Constructs a new instance of this class given an object to send the
047     * message to, a string naming the method to invoke and an argument count.
048     * Note that, if the object is an instance of <code>Class</code> it is
049     * assumed that the method is a static method on that class.
050     * 
051     * @param object
052     *            the object to send the message to
053     * @param method
054     *            the name of the method to invoke
055     * @param argCount
056     *            the number of arguments that the method takes
057     */
058    public Callback(Object object, String method, int argCount) {
059        this(object, method, argCount, false);
060    }
061
062    /**
063     * Constructs a new instance of this class given an object to send the
064     * message to, a string naming the method to invoke, an argument count and a
065     * flag indicating whether or not the arguments will be passed in an array.
066     * Note that, if the object is an instance of <code>Class</code> it is
067     * assumed that the method is a static method on that class.
068     * 
069     * @param object
070     *            the object to send the message to
071     * @param method
072     *            the name of the method to invoke
073     * @param argCount
074     *            the number of arguments that the method takes
075     * @param isArrayBased
076     *            <code>true</code> if the arguments should be passed in an
077     *            array and false otherwise
078     */
079    public Callback(Object object, String method, int argCount, boolean isArrayBased) {
080        this(object, method, argCount, isArrayBased, 0);
081    }
082
083    /**
084     * Constructs a new instance of this class given an object to send the
085     * message to, a string naming the method to invoke, an argument count, a
086     * flag indicating whether or not the arguments will be passed in an array
087     * and a value to return when an exception happens. Note that, if the object
088     * is an instance of <code>Class</code> it is assumed that the method is a
089     * static method on that class.
090     * 
091     * @param object
092     *            the object to send the message to
093     * @param method
094     *            the name of the method to invoke
095     * @param argCount
096     *            the number of arguments that the method takes
097     * @param isArrayBased
098     *            <code>true</code> if the arguments should be passed in an
099     *            array and false otherwise
100     * @param errorResult
101     *            the return value if the java code throws an exception
102     */
103    public Callback(Object object, String method, int argCount, boolean isArrayBased, long /* int */errorResult) {
104
105        /* Set the callback fields */
106        this.object = object;
107        this.method = method;
108        this.argCount = argCount;
109        this.isStatic = object instanceof Class<?>;
110        this.isArrayBased = isArrayBased;
111        this.errorResult = errorResult;
112
113        /* Inline the common cases */
114        if (isArrayBased) {
115            signature = SIGNATURE_N;
116        } else {
117            switch (argCount) {
118            case 0:
119                signature = SIGNATURE_0;
120                break; //$NON-NLS-1$
121            case 1:
122                signature = SIGNATURE_1;
123                break; //$NON-NLS-1$
124            case 2:
125                signature = SIGNATURE_2;
126                break; //$NON-NLS-1$
127            case 3:
128                signature = SIGNATURE_3;
129                break; //$NON-NLS-1$
130            case 4:
131                signature = SIGNATURE_4;
132                break; //$NON-NLS-1$
133            default:
134                signature = getSignature(argCount);
135            }
136        }
137
138        /* Bind the address */
139        address = bind(this, object, method, signature, argCount, isStatic, isArrayBased, errorResult);
140    }
141
142    /**
143     * Allocates the native level resources associated with the callback. This
144     * method is only invoked from within the constructor for the argument.
145     * 
146     * @param callback
147     *            the callback to bind
148     * @param object
149     *            the callback's object
150     * @param method
151     *            the callback's method
152     * @param signature
153     *            the callback's method signature
154     * @param argCount
155     *            the callback's method argument count
156     * @param isStatic
157     *            whether the callback's method is static
158     * @param isArrayBased
159     *            whether the callback's method is array based
160     * @param errorResult
161     *            the callback's error result
162     */
163    static native synchronized long /* int */ bind(Callback callback, Object object, String method, String signature, int argCount, boolean isStatic, boolean isArrayBased,
164            long /* int */errorResult);
165
166    /**
167     * Releases the native level resources associated with the callback, and
168     * removes all references between the callback and other objects. This helps
169     * to prevent (bad) application code from accidentally holding onto
170     * extraneous garbage.
171     */
172    public void dispose() {
173        if (object == null)
174            return;
175        unbind(this);
176        object = method = signature = null;
177        address = 0;
178    }
179
180    /**
181     * Returns the address of a block of machine code which will invoke the
182     * callback represented by the receiver.
183     * 
184     * @return the callback address
185     */
186    public long /* int */getAddress() {
187        return address;
188    }
189
190    /**
191     * Returns the SWT platform name.
192     * 
193     * @return the platform name of the currently running SWT
194     */
195    public static native String getPlatform();
196
197    /**
198     * Returns the number of times the system has been recursively entered
199     * through a callback.
200     * <p>
201     * Note: This should not be called by application code.
202     * </p>
203     * 
204     * @return the entry count
205     * 
206     * @since 2.1
207     */
208    public static native int getEntryCount();
209
210    static String getSignature(int argCount) {
211        String signature = "("; //$NON-NLS-1$
212        for (int i = 0; i < argCount; i++)
213            signature += PTR_SIGNATURE;
214        signature += ")" + PTR_SIGNATURE; //$NON-NLS-1$
215        return signature;
216    }
217
218    /**
219     * Indicates whether or not callbacks which are triggered at the native
220     * level should cause the messages described by the matching
221     * <code>Callback</code> objects to be invoked. This method is used to
222     * safely shut down SWT when it is run within environments which can
223     * generate spurious events.
224     * <p>
225     * Note: This should not be called by application code.
226     * </p>
227     * 
228     * @param enable
229     *            true if callbacks should be invoked
230     */
231    public static final native synchronized void setEnabled(boolean enable);
232
233    /**
234     * Returns whether or not callbacks which are triggered at the native level
235     * should cause the messages described by the matching <code>Callback</code>
236     * objects to be invoked. This method is used to safely shut down SWT when
237     * it is run within environments which can generate spurious events.
238     * <p>
239     * Note: This should not be called by application code.
240     * </p>
241     * 
242     * @return true if callbacks should not be invoked
243     */
244    public static final native synchronized boolean getEnabled();
245
246    /**
247     * Immediately wipes out all native level state associated with <em>all</em>
248     * callbacks.
249     * <p>
250     * <b>WARNING:</b> This operation is <em>extremely</em> dangerous, and
251     * should never be performed by application code.
252     * </p>
253     */
254    public static final native synchronized void reset();
255
256    /**
257     * Releases the native level resources associated with the callback.
258     * 
259     * @see #dispose
260     */
261    static final native synchronized void unbind(Callback callback);
262
263}