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     *******************************************************************************/
011    package 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    
023    public 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    }