KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > launching > JavaLaunchableTester


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.launching;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.core.expressions.PropertyTester;
22 import org.eclipse.core.resources.IContainer;
23 import org.eclipse.core.resources.IProject;
24 import org.eclipse.core.resources.IResource;
25 import org.eclipse.core.resources.ResourcesPlugin;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IAdaptable;
28 import org.eclipse.core.runtime.IPath;
29 import org.eclipse.core.runtime.NullProgressMonitor;
30 import org.eclipse.jdt.core.Flags;
31 import org.eclipse.jdt.core.IBuffer;
32 import org.eclipse.jdt.core.IClassFile;
33 import org.eclipse.jdt.core.IClasspathEntry;
34 import org.eclipse.jdt.core.ICompilationUnit;
35 import org.eclipse.jdt.core.IJavaElement;
36 import org.eclipse.jdt.core.IJavaProject;
37 import org.eclipse.jdt.core.IMember;
38 import org.eclipse.jdt.core.IMethod;
39 import org.eclipse.jdt.core.IOpenable;
40 import org.eclipse.jdt.core.IPackageFragment;
41 import org.eclipse.jdt.core.IPackageFragmentRoot;
42 import org.eclipse.jdt.core.ISourceRange;
43 import org.eclipse.jdt.core.IType;
44 import org.eclipse.jdt.core.JavaCore;
45 import org.eclipse.jdt.core.JavaModelException;
46 import org.eclipse.jdt.core.Signature;
47 import org.eclipse.jdt.core.ToolFactory;
48 import org.eclipse.jdt.core.compiler.IScanner;
49 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
50 import org.eclipse.jdt.core.compiler.InvalidInputException;
51
52 /**
53  * Property tester for context launching menu.
54  *
55  * @since 3.2
56  */

57 public class JavaLaunchableTester extends PropertyTester {
58
59     /**
60      * name for the "has main" property
61      */

62     private static final String JavaDoc PROPERTY_HAS_MAIN = "hasMain"; //$NON-NLS-1$
63

64     /**
65      * name for the "has method" property
66      */

67     private static final String JavaDoc PROPERTY_HAS_METHOD = "hasMethod"; //$NON-NLS-1$
68

69     /**
70      * name for the "has method with annotation" property
71      */

72     private static final String JavaDoc PROPERTY_HAS_METHOD_WITH_ANNOTATION = "hasMethodWithAnnotation"; //$NON-NLS-1$
73

74     /**
75      * name for the "has type with annotation" property
76      */

77     private static final String JavaDoc PROPERTY_HAS_TYPE_WITH_ANNOTATION = "hasTypeWithAnnotation"; //$NON-NLS-1$
78

79     /**
80      * name for the "extends class" property
81      */

82     private static final String JavaDoc PROPERTY_EXTENDS_CLASS = "extendsClass"; //$NON-NLS-1$
83

84     /**
85      * "is container" property
86      */

87     private static final String JavaDoc PROPERTY_IS_CONTAINER = "isContainer"; //$NON-NLS-1$
88

89     /**
90      * "is package fragment" property
91      * @since 3.3
92      */

93     private static final String JavaDoc PROPERTY_IS_PACKAGE_FRAGMENT = "isPackageFragment"; //$NON-NLS-1$
94

95     /**
96      * "is package fragment root" property
97      * @since 3.3
98      */

99     private static final String JavaDoc PROPERTY_IS_PACKAGE_FRAGMENT_ROOT = "isPackageFragmentRoot"; //$NON-NLS-1$
100

101     /**
102      * name for the PROPERTY_PROJECT_NATURE property
103      */

104     private static final String JavaDoc PROPERTY_PROJECT_NATURE = "hasProjectNature"; //$NON-NLS-1$
105

106     /**
107      * name for the "extends interface" property
108      */

109     private static final String JavaDoc PROPERTY_EXTENDS_INTERFACE = "extendsInterface"; //$NON-NLS-1$
110

111     /**
112      * name for the PROPERTY_HAS_SWT_ON_PATH property
113      */

114     private static final String JavaDoc PROPERTY_BUILDPATH_REFERENCE = "buildpathReference"; //$NON-NLS-1$
115

116     /**
117      * Map of modifier text to corresponding flag (Integer)
118      */

119     private static Map JavaDoc fgModifiers = new HashMap JavaDoc();
120     
121     private static final int FLAGS_MASK= Flags.AccPublic | Flags.AccProtected | Flags.AccPrivate | Flags.AccStatic
122         | Flags.AccFinal | Flags.AccSynchronized | Flags.AccAbstract | Flags.AccNative;
123     
124     
125     static {
126         fgModifiers.put("public", new Integer JavaDoc(Flags.AccPublic)); //$NON-NLS-1$
127
fgModifiers.put("protected", new Integer JavaDoc(Flags.AccProtected)); //$NON-NLS-1$
128
fgModifiers.put("private", new Integer JavaDoc(Flags.AccPrivate)); //$NON-NLS-1$
129
fgModifiers.put("static", new Integer JavaDoc(Flags.AccStatic)); //$NON-NLS-1$
130
fgModifiers.put("final", new Integer JavaDoc(Flags.AccFinal)); //$NON-NLS-1$
131
fgModifiers.put("synchronized", new Integer JavaDoc(Flags.AccSynchronized)); //$NON-NLS-1$
132
fgModifiers.put("abstract", new Integer JavaDoc(Flags.AccAbstract)); //$NON-NLS-1$
133
fgModifiers.put("native", new Integer JavaDoc(Flags.AccNative)); //$NON-NLS-1$
134
}
135         
136     /**
137      * gets the type of the IJavaElement
138      * @param element the element to inspect
139      * @return the type
140      * @throws JavaModelException
141      */

142     private IType getType(IJavaElement element) {
143         IType type = null;
144         if (element instanceof ICompilationUnit) {
145             type= ((ICompilationUnit) element).findPrimaryType();
146         }
147         else if (element instanceof IClassFile) {
148             type = ((IClassFile)element).getType();
149         }
150         else if (element instanceof IType) {
151             type = (IType) element;
152         }
153         else if (element instanceof IMember) {
154             type = ((IMember)element).getDeclaringType();
155         }
156         return type;
157     }
158     
159     /**
160      * Determines is the java element contains a main method.
161      *
162      * @param element the element to check for the method
163      * @return true if the method is found in the element, false otherwise
164      */

165     private boolean hasMain(IJavaElement element) {
166         try {
167             IType type = getType(element);
168             if(type != null && type.exists()) {
169                 if(hasMainMethod(type)) {
170                     return true;
171                 }
172                 //failed to find in public type, check static inner types
173
IJavaElement[] children = type.getChildren();
174                 for(int i = 0; i < children.length; i++) {
175                     if(hasMainInChildren(getType(children[i]))) {
176                         return true;
177                     }
178                 }
179             }
180         }
181         catch (JavaModelException e) {}
182         catch (CoreException ce){}
183         return false;
184     }
185     
186     /**
187      * Returns if the specified <code>IType</code> has a main method
188      * @param type the type to inspect for a main type
189      * @return true if the specified type has a main method, false otherwise
190      * @throws JavaModelException
191      * @since 3.3
192      */

193     private boolean hasMainMethod(IType type) throws JavaModelException {
194         IMethod[] methods = type.getMethods();
195         for (int i= 0; i < methods.length; i++) {
196             if(methods[i].isMainMethod()) {
197                 return true;
198             }
199         }
200         return false;
201     }
202     
203     /**
204      * This method asks the specified <code>IType</code> if it has a main method, if not it recurses through all of its children
205      * When recursing we only care about child <code>IType</code>s that are static.
206      * @param type the <code>IType</code> to inspect for a main method
207      * @return true if a main method was found in specified <code>IType</code>, false otherwise
208      * @throws CoreException
209      * @since 3.3
210      */

211     private boolean hasMainInChildren(IType type) throws CoreException {
212         if(type.isClass() & Flags.isStatic(type.getFlags())) {
213             if(hasMainMethod(type)) {
214                 return true;
215             }
216             else {
217                 IJavaElement[] children = type.getChildren();
218                 for(int i = 0; i < children.length; i++) {
219                     if(children[i].getElementType() == IJavaElement.TYPE) {
220                         return hasMainInChildren((IType) children[i]);
221                     }
222                 }
223             }
224         }
225         return false;
226     }
227     
228     /**
229      * Determines is the java element contains a specific method.
230      * <p>
231      * The syntax for the property tester is of the form: methodname,
232      * signature, modifiers.
233      * </p>
234      * <ol>
235      * <li>methodname - case sensitive method name, required. For example,
236      * <code>toString</code>.</li>
237      * <li>signature - JLS style method signature, required. For example,
238      * <code>(QString;)V</code>.</li>
239      * <li>modifiers - optional space separated list of modifiers, for
240      * example, <code>public static</code>.</li>
241      * </ol>
242      * @param element the element to check for the method
243      * @param args first arg is method name, secondary args are parameter types signatures
244      * @return true if the method is found in the element, false otherwise
245      */

246     private boolean hasMethod(IJavaElement element, Object JavaDoc[] args) {
247         try {
248             if (args.length > 1) {
249                 IType type = getType(element);
250                 if (type != null && type.exists()) {
251                     String JavaDoc name = (String JavaDoc) args[0];
252                     String JavaDoc signature = (String JavaDoc) args[1];
253                     String JavaDoc[] parms = Signature.getParameterTypes(signature);
254                     String JavaDoc returnType = Signature.getReturnType(signature);
255                     IMethod candidate = type.getMethod(name, parms);
256                     if (candidate.exists()) {
257                         // check return type
258
if (candidate.getReturnType().equals(returnType)) {
259                             // check modifiers
260
if (args.length > 2) {
261                                 String JavaDoc modifierText = (String JavaDoc) args[2];
262                                 String JavaDoc[] modifiers = modifierText.split(" "); //$NON-NLS-1$
263
int flags = 0;
264                                 for (int j = 0; j < modifiers.length; j++) {
265                                     String JavaDoc modifier = modifiers[j];
266                                     Integer JavaDoc flag = (Integer JavaDoc) fgModifiers.get(modifier);
267                                     if (flag != null) {
268                                         flags = flags | flag.intValue();
269                                     }
270                                 }
271                                 if (candidate.getFlags() == flags) {
272                                     return true;
273                                 }
274                             }
275                         }
276                     }
277                 }
278             }
279         }
280         catch (JavaModelException e) {}
281         return false;
282     }
283     
284     /**
285      * Determines is the java element contains a type with a specific annotation.
286      * <p>
287      * The syntax for the property tester is of the form: qualified or unqualified annotation name
288      * <li>qualified or unqualified annotation name, required. For example,
289      * <code>org.junit.JUnit</code>.</li>
290      * </ol>
291      * @param element the element to check for the method
292      * @param annotationName the qualified or unqualified name of the annotation to look for
293      * @return true if the type is found in the element, false otherwise
294      */

295     private boolean hasTypeWithAnnotation(IJavaElement element, String JavaDoc annotationType) {
296         try {
297             IType type= getType(element);
298             if (type == null || !type.exists()) {
299                 return false;
300             }
301
302             IBuffer buffer= null;
303             IOpenable openable= type.getOpenable();
304             if (openable instanceof ICompilationUnit) {
305                 buffer= ((ICompilationUnit) openable).getBuffer();
306             } else if (openable instanceof IClassFile) {
307                 buffer= ((IClassFile) openable).getBuffer();
308             }
309             if (buffer == null) {
310                 return false;
311             }
312             
313             ISourceRange sourceRange= type.getSourceRange();
314             ISourceRange nameRange= type.getNameRange();
315             if (sourceRange != null && nameRange != null) {
316                 IScanner scanner= ToolFactory.createScanner(false, false, true, false);
317                 scanner.setSource(buffer.getCharacters());
318                 scanner.resetTo(sourceRange.getOffset(), nameRange.getOffset());
319                 if (findAnnotation(scanner, annotationType)) {
320                     return true;
321                 }
322             }
323         }
324         catch (JavaModelException e) {}
325         catch (InvalidInputException e) {}
326         return false;
327     }
328
329     
330     /**
331      * Determines is the java element contains a method with a specific annotation.
332      * <p>
333      * The syntax for the property tester is of the form: qualified or unqualified annotation name, modifiers
334      * <li>qualified or unqualified annotation name, required. For example,
335      * <code>org.junit.JUnit</code>.</li>
336      * <li>modifiers - optional space separated list of modifiers, for
337      * example, <code>public static</code>.</li>
338      * </ol>
339      * @param element the element to check for the method
340      * @param annotationName the qualified or unqualified name of the annotation to look for
341      * @return true if the method is found in the element, false otherwise
342      */

343     private boolean hasMethodWithAnnotation(IJavaElement element, Object JavaDoc[] args) {
344         try {
345             String JavaDoc annotationType= (String JavaDoc) args[0];
346             int flags = 0;
347             if (args.length > 1) {
348                 String JavaDoc[] modifiers = ((String JavaDoc) args[1]).split(" "); //$NON-NLS-1$
349
for (int j = 0; j < modifiers.length; j++) {
350                     String JavaDoc modifier = modifiers[j];
351                     Integer JavaDoc flag = (Integer JavaDoc) fgModifiers.get(modifier);
352                     if (flag != null) {
353                         flags = flags | flag.intValue();
354                     }
355                 }
356             } else {
357                 flags= -1;
358             }
359             
360             IType type= getType(element);
361             if (type == null || !type.exists()) {
362                 return false;
363             }
364             IMethod[] methods= type.getMethods();
365             if (methods.length == 0) {
366                 return false;
367             }
368
369             IBuffer buffer= null;
370             IOpenable openable= type.getOpenable();
371             if (openable instanceof ICompilationUnit) {
372                 buffer= ((ICompilationUnit) openable).getBuffer();
373             } else if (openable instanceof IClassFile) {
374                 buffer= ((IClassFile) openable).getBuffer();
375             }
376             if (buffer == null) {
377                 return false;
378             }
379             IScanner scanner=null; // delay initialization
380

381             for (int i= 0; i < methods.length; i++) {
382                 IMethod curr= methods[i];
383                 if (curr.isConstructor() || (flags != -1 && flags != (curr.getFlags() & FLAGS_MASK))) {
384                     continue;
385                 }
386                 
387                 
388                 ISourceRange sourceRange= curr.getSourceRange();
389                 ISourceRange nameRange= curr.getNameRange();
390                 if (sourceRange != null && nameRange != null) {
391                     if (scanner == null) {
392                         scanner= ToolFactory.createScanner(false, false, true, false);
393                         scanner.setSource(buffer.getCharacters());
394                     }
395                     scanner.resetTo(sourceRange.getOffset(), nameRange.getOffset());
396                     if (findAnnotation(scanner, annotationType)) {
397                         return true;
398                     }
399                 }
400             }
401         } catch (JavaModelException e) {
402         } catch (InvalidInputException e) {
403         }
404         return false;
405     }
406     
407     private boolean findAnnotation(IScanner scanner, String JavaDoc annotationName) throws InvalidInputException {
408         String JavaDoc simpleName= Signature.getSimpleName(annotationName);
409         StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
410         int tok= scanner.getNextToken();
411         while (tok != ITerminalSymbols.TokenNameEOF) {
412             if (tok == ITerminalSymbols.TokenNameAT) {
413                 buf.setLength(0);
414                 tok= readName(scanner, buf);
415                 String JavaDoc name= buf.toString();
416                 if (name.equals(annotationName) || name.equals(simpleName) || name.endsWith('.' + simpleName)) {
417                     return true;
418                 }
419             } else {
420                 tok= scanner.getNextToken();
421             }
422         }
423         return false;
424     }
425
426     private int readName(IScanner scanner, StringBuffer JavaDoc buf) throws InvalidInputException {
427         int tok= scanner.getNextToken();
428         while (tok == ITerminalSymbols.TokenNameIdentifier) {
429             buf.append(scanner.getCurrentTokenSource());
430             tok= scanner.getNextToken();
431             if (tok != ITerminalSymbols.TokenNameDOT) {
432                 return tok;
433             }
434             buf.append('.');
435             tok= scanner.getNextToken();
436         }
437         return tok;
438     }
439
440     /**
441      * determines if the project selected has the specified nature
442      * @param resource the resource to get the project for
443      * @param ntype the specified nature type
444      * @return true if the specified nature matches the project, false otherwise
445      */

446     private boolean hasProjectNature(IJavaElement element, String JavaDoc ntype) {
447         try {
448             if(element != null) {
449                 IJavaProject jproj = element.getJavaProject();
450                 if(jproj != null) {
451                     IProject proj = jproj.getProject();
452                     return proj.isAccessible() && proj.hasNature(ntype);
453                 }
454             }
455             return false;
456         }
457         catch (CoreException e) {return false;}
458     }
459     
460     /**
461      * Determines if the element has qname as a parent class
462      * @param element the element to check for the parent class definition
463      * @param qname the fully qualified name of the (potential) parent class
464      * @return true if qname is a parent class, false otherwise
465      */

466     private boolean hasSuperclass(IJavaElement element, String JavaDoc qname) {
467         try {
468             IType type = getType(element);
469             if(type != null) {
470                 IType[] stypes = type.newSupertypeHierarchy(new NullProgressMonitor()).getAllSuperclasses(type);
471                 for(int i = 0; i < stypes.length; i++) {
472                     if(stypes[i].getFullyQualifiedName().equals(qname) || stypes[i].getElementName().equals(qname)) {
473                         return true;
474                     }
475                 }
476             }
477         }
478         catch(JavaModelException e) {}
479         return false;
480     }
481     
482     /**
483      * Determines if an item or list of items are found on the build path.
484      * Once any one single items matches though, the method returns true, this method is intended
485      * to be used in OR like situations, where we do not care if all of the items are on the build path, only that one
486      * of them is.
487      *
488      * @param element the element whose build path should be checked
489      * @param args the value(s) to search for on the build path
490      * @return true if any one of the args is found on the build path
491      */

492     private boolean hasItemOnBuildPath(IJavaElement element, Object JavaDoc[] args) {
493         if(element != null && args != null) {
494             IJavaProject project = element.getJavaProject();
495             Set JavaDoc searched = new HashSet JavaDoc();
496             searched.add(project);
497             return hasItemsOnBuildPath(project, searched, args);
498         }
499         return false;
500     }
501     
502     private boolean hasItemsOnBuildPath(IJavaProject project, Set JavaDoc searched, Object JavaDoc[] args) {
503         try {
504             List JavaDoc projects = new ArrayList JavaDoc();
505             if(project != null && project.exists()) {
506                 IClasspathEntry[] entries = project.getResolvedClasspath(true);
507                 for(int i = 0; i < entries.length; i++) {
508                     IClasspathEntry entry = entries[i];
509                     IPath path = entry.getPath();
510                     String JavaDoc spath = path.toPortableString();
511                     for(int j = 0; j < args.length; j++) {
512                         if(spath.lastIndexOf((String JavaDoc)args[j]) != -1) {
513                             return true;
514                         }
515                     }
516                     if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
517                         String JavaDoc name = entry.getPath().lastSegment();
518                         IProject dep = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
519                         IJavaProject javaProject = JavaCore.create(dep);
520                         if (!searched.contains(javaProject)) {
521                             projects.add(javaProject);
522                         }
523                     }
524                 }
525             }
526             // search referenced projects
527
Iterator JavaDoc iterator = projects.iterator();
528             while (iterator.hasNext()) {
529                 IJavaProject jp = (IJavaProject) iterator.next();
530                 searched.add(jp);
531                 if (hasItemsOnBuildPath(jp, searched, args)) {
532                     return true;
533                 }
534             }
535         } catch (JavaModelException e) {}
536         return false;
537     }
538     
539     /**
540      * determines if the element implements a given interface
541      * @param element the element to check for the interface
542      * @param qname the fully qualified name of the interface to check for
543      * @return true if the element does implement the interface, false otherwise
544      */

545     private boolean implementsInterface(IJavaElement element, String JavaDoc qname) {
546         try {
547             IType type = getType(element);
548             if(type != null) {
549                 IType[] itypes = type.newSupertypeHierarchy(new NullProgressMonitor()).getAllInterfaces();
550                 for(int i = 0; i < itypes.length; i++) {
551                     if(itypes[i].getFullyQualifiedName().equals(qname)) {
552                         return true;
553                     }
554                 }
555             }
556         }
557         catch(JavaModelException e) {}
558         return false;
559     }
560     
561     /**
562      * Method runs the tests defined from extension points for Run As... and Debug As... menu items.
563      * Currently this test optimistically considers everything not a source file. In this context we
564      * consider an optimistic approach to mean that the test will always return true.
565      *
566      * There are many reasons for the optimistic choice some of them are outlined below.
567      * <ul>
568      * <li>Performance (in terms of time needed to display menu) cannot be preserved. To know what to allow
569      * in any one of the menus we would have to search all of the children of the container to determine what it contains
570      * and what can be launched by what.</li>
571      * <li>If inspection of children of containers were done, a user might want to choose a different launch type, even though our tests
572      * filter it out.</li>
573      * </ul>
574      * @see org.eclipse.core.expressions.IPropertyTester#test(java.lang.Object, java.lang.String, java.lang.Object[], java.lang.Object)
575      * @since 3.2
576      * @return true if the specified tests pass, or the context is a container, false otherwise
577      */

578     public boolean test(Object JavaDoc receiver, String JavaDoc property, Object JavaDoc[] args, Object JavaDoc expectedValue) {
579         if (PROPERTY_IS_CONTAINER.equals(property)) {
580             if (receiver instanceof IAdaptable) {
581                 IResource resource = (IResource)((IAdaptable)receiver).getAdapter(IResource.class);
582                 if (resource != null) {
583                     return resource instanceof IContainer;
584                 }
585             }
586             return false;
587         }
588         IJavaElement element = null;
589         if (receiver instanceof IAdaptable) {
590             element = (IJavaElement) ((IAdaptable)receiver).getAdapter(IJavaElement.class);
591             if(element != null) {
592                 if(!element.exists()) {
593                     return false;
594                 }
595             }
596         }
597         if(PROPERTY_HAS_MAIN.equals(property)) {
598             return hasMain(element);
599         }
600         if (PROPERTY_HAS_METHOD.equals(property)) {
601             return hasMethod(element, args);
602         }
603         if (PROPERTY_HAS_METHOD_WITH_ANNOTATION.equals(property)) {
604             return hasMethodWithAnnotation(element, args);
605         }
606         if (PROPERTY_HAS_TYPE_WITH_ANNOTATION.equals(property)) {
607             return hasTypeWithAnnotation(element, (String JavaDoc)args[0]);
608         }
609         if(PROPERTY_BUILDPATH_REFERENCE.equals(property)) {
610             return hasItemOnBuildPath(element, args);
611         }
612         if(PROPERTY_EXTENDS_CLASS.equals(property)) {
613             return hasSuperclass(element, (String JavaDoc)args[0]);
614         }
615         if(PROPERTY_PROJECT_NATURE.equals(property)) {
616             return hasProjectNature(element, (String JavaDoc)args[0]);
617         }
618         if(PROPERTY_EXTENDS_INTERFACE.equals(property)) {
619             return implementsInterface(element, (String JavaDoc)args[0]);
620         }
621         if (PROPERTY_IS_PACKAGE_FRAGMENT.equals(property)) {
622             return element instanceof IPackageFragment;
623         }
624         if (PROPERTY_IS_PACKAGE_FRAGMENT_ROOT.equals(property)) {
625             return element instanceof IPackageFragmentRoot;
626         }
627         return false;
628     }
629     
630 }
631
Popular Tags