001    package edu.rice.cs.cunit.threadCheck.predicates;
002    
003    import java.awt.*;
004    import java.util.HashSet;
005    
006    /**
007     * Class containing several common predicates.
008     * @author Mathias Ricken
009     */
010    public class ThreadCheckPredicates {
011        /**
012         * Return true if the current thread is the event thread.
013         * @param thisObject "this" at the time of the check, or null if not available; ignored by this method
014         * @return true if the current thread is the event thread
015         */
016        public static boolean checkEventThread(Object thisObject) {
017            return EventQueue.isDispatchThread();
018        }
019    
020        /**
021         * Return true if the current thread is the event thread, or if thisObject is an instance of a subclass of
022         * java.awt.Component and that component has not been realized yet.
023         * @param thisObject "this" at the time of the check, or null if not available; ignored by this method
024         * @return true if the current thread is the event thread, or thisObject is a component that has not been realized
025         */
026        public static boolean checkEventThreadAfterRealized(Object thisObject) {
027            if (thisObject!=null) {
028                // non-static context
029                if (thisObject instanceof Component) {
030                    // subclass of java.awt.Component
031                    Component thisComponent = (Component)thisObject;
032                    if (!thisComponent.isDisplayable()) {
033                        // and not realized yet; any thread is ok
034                        return true;
035                    }
036                }
037                return EventQueue.isDispatchThread();
038            }
039            else {
040                // static context
041                return EventQueue.isDispatchThread();
042            }
043        }
044    
045        /**
046         * Return true if the current thread's name equals the specified string
047         * @param thisObject "this" at the time of the check, or null if not available; ignored by this method
048         * @param value string to compare the current thread's name to
049         * @param regex true if value should be treated as a regular expression
050         * @return true if the current thread's name equals the specified string
051         */
052        public static boolean checkName(Object thisObject, String value, boolean regex) {
053            if (regex) {
054                return Thread.currentThread().getName().matches(value);
055            }
056            else {
057                return Thread.currentThread().getName().equals(value);
058            }
059        }
060    
061        /**
062         * Return true if the current thread's group equals the specified string
063         * @param thisObject "this" at the time of the check, or null if not available; ignored by this method
064         * @param value string to compare the current thread's group to
065         * @param regex true if value should be treated as a regular expression
066         * @return true if the current thread's group equals the specified string
067         */
068        public static boolean checkGroup(Object thisObject, String value, boolean regex) {
069            if (regex) {
070                return Thread.currentThread().getThreadGroup().getName().matches(value);
071            }
072            else {
073                return Thread.currentThread().getThreadGroup().getName().equals(value);
074            }
075        }
076        
077        /**
078         * Return true if the current thread owns the monitor of the object.
079         * If this method is directly used in a predicate annotation, then the object
080         * passed is "this".
081         * @param o object whose monitor should be checked; must be non-null
082         * @return true if the current thread owns the monitor (false if o is null)
083         */
084        public static boolean checkMonitorOwned(Object o) {
085            if (o==null) return false;
086            boolean interrupted = true;
087            while(interrupted) {
088                try {
089                    o.wait(10);
090                    interrupted = false;
091                }
092                catch(InterruptedException e) { /* ignore */ }
093                catch(IllegalMonitorStateException e) { return false; }
094            }
095            return true;
096        }
097    
098        /**
099         * Return true if the current thread does not own the monitor of the object.
100         * If this method is directly used in a predicate annotation, then the object
101         * passed is "this".
102         * @param o object whose monitor should be checked; must be non-null
103         * @return true if the current thread does not own the monitor (false if o is null)
104         */
105        public static boolean checkMonitorNotOwned(Object o) {
106            return !checkMonitorOwned(o);
107        }
108    
109        /**
110         * Return true if the current thread owns the monitor of the object
111         * with index value in the array of method arguments
112         * @param thisObject object that represents "this", or null if static
113         * @param args array of method arguments
114         * @param value index of the method argument that should be checked
115         * @return true if the current thread owns the monitor of the argument (false if value is out of range)
116         */
117        public static boolean checkMonitorOwnedArgument(Object thisObject, Object[] args, int value) {
118            if (value>=args.length) { return false; }
119            return checkMonitorOwned(args[value]);
120        }
121    
122        /**
123         * Return true if the current thread does not own the monitor of the object
124         * with index value in the array of method arguments
125         * @param thisObject object that represents "this", or null if static
126         * @param args array of method arguments
127         * @param value index of the method argument that should be checked
128         * @return true if the current thread does not own the monitor of the argument (false if value is out of range)
129         */
130        public static boolean checkMonitorNotOwnedArgument(Object thisObject, Object[] args, int value) {
131            if (value>=args.length) { return false; }
132            return ThreadCheckPredicates.checkMonitorNotOwned(args[value]);
133        }
134            
135        /**
136         * Return true if the any thread owns the monitor of the object.
137         * If this method is directly used in a predicate annotation, then the object
138         * passed is "this".
139         * @param o object whose monitor should be checked; must be non-null
140         * @return true if the any thread owns the monitor (false if o is null)
141         */
142        public static boolean checkMonitorOwnedByAnyThread(final Object o) {
143            if (o==null) return false;
144            final Boolean[] owned = new Boolean[] { null };
145            Thread inquirer = new Thread(new Runnable() {
146                public void run() {
147                    final Thread inquirerThread = Thread.currentThread();
148                    Thread acquirer = new Thread(new Runnable() {
149                        public void run() {
150                            synchronized(o) {
151                                owned[0] = false;
152                                inquirerThread.interrupt();
153                            }
154                        }
155                    });
156                    acquirer.start();
157                    synchronized(this) {
158                        while (owned[0]==null) {
159                            try {
160                                wait(10);
161                                owned[0] = true;
162                                return;
163                            }
164                            catch(InterruptedException e) {
165                                if (!owned[0]) {
166                                    return;
167                                }
168                            }
169                        }
170                    }
171                }
172            });
173            
174            inquirer.start();
175            try {
176                inquirer.join();
177            }
178            catch(InterruptedException e) { /* ignore */ }
179            return owned[0];
180        }
181    
182        /**
183         * Return true if the no thread owns the monitor of the object.
184         * If this method is directly used in a predicate annotation, then the object
185         * passed is "this".
186         * @param o object whose monitor should be checked; must be non-null
187         * @return true if the no thread owns the monitor (false if o is null)
188         */
189        public static boolean checkMonitorNotOwnedByAnyThread(Object o) {
190            return !checkMonitorOwnedByAnyThread(o);
191        }
192    
193        /**
194         * Return true if the any thread owns the monitor of the object
195         * with index value in the array of method arguments
196         * @param thisObject object that represents "this", or null if static
197         * @param args array of method arguments
198         * @param value index of the method argument that should be checked
199         * @return true if the any thread owns the monitor of the argument (false if value is out of range)
200         */
201        public static boolean checkMonitorOwnedArgumentByAnyThread(Object thisObject, Object[] args, int value) {
202            if (value>=args.length) { return false; }
203            return checkMonitorOwnedByAnyThread(args[value]);
204        }
205    
206        /**
207         * Return true if the current thread does not own the monitor of the object
208         * with index value in the array of method arguments
209         * @param thisObject object that represents "this", or null if static
210         * @param args array of method arguments
211         * @param value index of the method argument that should be checked
212         * @return true if the current thread does not own the monitor of the argument (false if value is out of range)
213         */
214        public static boolean checkMonitorNotOwnedArgumentByAnyThread(Object thisObject, Object[] args, int value) {
215            if (value>=args.length) { return false; }
216            return ThreadCheckPredicates.checkMonitorNotOwnedByAnyThread(args[value]);
217        }
218        
219        /**
220         * Return true if the object with index value in the array of method arguments is null.
221         * @param thisObject object that represents "this", or null if static
222         * @param args array of method arguments
223         * @param value index of the method argument that should be checked
224         * @return true if the argument is null (false if value is out of range)
225         */
226        public static boolean checkNullArgument(Object thisObject, Object[] args, int value) {
227            if (value>=args.length) { return false; }
228            return args[value]==null;
229        }
230    
231        /**
232         * Return true if the object with index value in the array of method arguments is not null.
233         * @param thisObject object that represents "this", or null if static
234         * @param args array of method arguments
235         * @param value index of the method argument that should be checked
236         * @return true if the argument is not null (false if value is out of range)
237         */
238        public static boolean checkNotNullArgument(Object thisObject, Object[] args, int value) {
239            if (value>=args.length) { return false; }
240            return args[value]!=null;
241        }
242    
243        /**
244         * Return true if the object with the specified index is a Number and meeds the bounds.
245         * @param thisObject object that represents "this", or null if static
246         * @param args array of method arguments
247         * @param mode bounding mode
248         * @param index index of the method argument that should be checked
249         * @param bound bound
250         * @param upperBound upper bound
251         * @return true if the number meets the bound, false otherwise, if index is out of range, or if the argument is not a Number
252         */
253        public static boolean checkNumberBoundedArgument(Object thisObject, Object[] args,
254                                                         NumberBoundedArgument.Mode mode,
255                                                         int index,
256                                                         double bound,
257                                                         double upperBound) {
258            if (index>=args.length) { return false; }
259            if (args[index]==null) { return false; }
260            if (!(args[index] instanceof Number)) {
261                return false;
262            }
263            Number n = ((Number)args[index]);
264            switch(mode) {
265                case LESS:
266                    return n.doubleValue()<bound;
267                case LESS_EQ:
268                    return n.doubleValue()<=bound;
269                case GREATER:
270                    return n.doubleValue()>bound;
271                case GREATER_EQ:
272                    return n.doubleValue()>=bound;
273                case IN_EQ:
274                    return (n.doubleValue()<=upperBound) && (n.doubleValue()>=bound);
275                case IN:
276                    return (n.doubleValue()<upperBound) && (n.doubleValue()>bound);
277                case OUT_EQ:
278                    return (n.doubleValue()<=bound) || (n.doubleValue()>=upperBound);
279                case OUT:
280                    return (n.doubleValue()<bound) || (n.doubleValue()>upperBound);
281            }
282            return false;
283        }
284    
285        /**
286         * Return true if the object with the specified indices are all distinct.
287         * @param thisObject object that represents "this", or null if static
288         * @param args array of method arguments
289         * @param value array of indices of the method argument that should be checked
290         * @return true if the arguments are all distinct, false otherwise, if value is out of range, or if fewer than two indices are specified
291         */
292        public static boolean checkDistinctArguments(Object thisObject, Object[] args,
293                                                     int[] value) {
294            if (value.length<2) { return false; }
295            HashSet<Object> found = new HashSet<Object>();
296            for (int i=0;i< value.length;++i) {
297                if (found.contains(args[i])) { return false; }
298                found.add(args[i]);
299            }
300            return true;
301        }
302    
303        /**
304         * Return true if the object with the specified indices are all the same.
305         * @param thisObject object that represents "this", or null if static
306         * @param args array of method arguments
307         * @param value array of indices of the method argument that should be checked
308         * @return true if the arguments are all the same, false otherwise, if value is out of range, or if fewer than two indices are specified
309         */
310        public static boolean checkSameArguments(Object thisObject, Object[] args,
311                                                 int[] value) {
312            if (value.length<2) { return false; }
313            for (int i=1;i< value.length;++i) {
314                if (!args[0].equals(args[i])) { return false; }
315            }
316            return true;
317        }
318    }