KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > util > HandleFactory


1 /*******************************************************************************
2  * Copyright (c) 2000, 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.core.util;
12
13 import java.util.HashMap JavaDoc;
14 import java.util.HashSet JavaDoc;
15
16 import org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.ResourcesPlugin;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.core.runtime.Path;
22 import org.eclipse.jdt.core.IClassFile;
23 import org.eclipse.jdt.core.IClasspathEntry;
24 import org.eclipse.jdt.core.ICompilationUnit;
25 import org.eclipse.jdt.core.IJavaElement;
26 import org.eclipse.jdt.core.IJavaProject;
27 import org.eclipse.jdt.core.IMember;
28 import org.eclipse.jdt.core.IPackageFragment;
29 import org.eclipse.jdt.core.IPackageFragmentRoot;
30 import org.eclipse.jdt.core.IType;
31 import org.eclipse.jdt.core.JavaCore;
32 import org.eclipse.jdt.core.JavaModelException;
33 import org.eclipse.jdt.core.compiler.CharOperation;
34 import org.eclipse.jdt.core.search.IJavaSearchScope;
35 import org.eclipse.jdt.internal.compiler.ast.*;
36 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
37 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
38 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
39 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
40 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
41 import org.eclipse.jdt.internal.compiler.lookup.Scope;
42 import org.eclipse.jdt.internal.core.*;
43 import org.eclipse.jdt.internal.core.JavaModel;
44 import org.eclipse.jdt.internal.core.JavaModelManager;
45 import org.eclipse.jdt.internal.core.JavaProject;
46 import org.eclipse.jdt.internal.core.Openable;
47 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
48 import org.eclipse.jdt.internal.core.util.Util;
49
50 /**
51  * Creates java element handles.
52  */

53 public class HandleFactory {
54
55     /**
56      * Cache package fragment root information to optimize speed performance.
57      */

58     private String JavaDoc lastPkgFragmentRootPath;
59     private IPackageFragmentRoot lastPkgFragmentRoot;
60
61     /**
62      * Cache package handles to optimize memory.
63      */

64     private HashtableOfArrayToObject packageHandles;
65
66     private JavaModel javaModel;
67
68     public HandleFactory() {
69         this.javaModel = JavaModelManager.getJavaModelManager().getJavaModel();
70     }
71     
72
73     /**
74      * Creates an Openable handle from the given resource path.
75      * The resource path can be a path to a file in the workbench (eg. /Proj/com/ibm/jdt/core/HandleFactory.java)
76      * or a path to a file in a jar file - it then contains the path to the jar file and the path to the file in the jar
77      * (eg. c:/jdk1.2.2/jre/lib/rt.jar|java/lang/Object.class or /Proj/rt.jar|java/lang/Object.class)
78      * NOTE: This assumes that the resource path is the toString() of an IPath,
79      * in other words, it uses the IPath.SEPARATOR for file path
80      * and it uses '/' for entries in a zip file.
81      * If not null, uses the given scope as a hint for getting Java project handles.
82      */

83     public Openable createOpenable(String JavaDoc resourcePath, IJavaSearchScope scope) {
84         int separatorIndex;
85         if ((separatorIndex= resourcePath.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR)) > -1) {
86             // path to a class file inside a jar
87
// Optimization: cache package fragment root handle and package handles
88
int rootPathLength;
89             if (this.lastPkgFragmentRootPath == null
90                     || (rootPathLength = this.lastPkgFragmentRootPath.length()) != resourcePath.length()
91                     || !resourcePath.regionMatches(0, this.lastPkgFragmentRootPath, 0, rootPathLength)) {
92                 String JavaDoc jarPath= resourcePath.substring(0, separatorIndex);
93                 IPackageFragmentRoot root= this.getJarPkgFragmentRoot(jarPath, scope);
94                 if (root == null)
95                     return null; // match is outside classpath
96
this.lastPkgFragmentRootPath= jarPath;
97                 this.lastPkgFragmentRoot= root;
98                 this.packageHandles= new HashtableOfArrayToObject(5);
99             }
100             // create handle
101
String JavaDoc classFilePath= resourcePath.substring(separatorIndex + 1);
102             String JavaDoc[] simpleNames = new Path(classFilePath).segments();
103             String JavaDoc[] pkgName;
104             int length = simpleNames.length-1;
105             if (length > 0) {
106                 pkgName = new String JavaDoc[length];
107                 System.arraycopy(simpleNames, 0, pkgName, 0, length);
108             } else {
109                 pkgName = CharOperation.NO_STRINGS;
110             }
111             IPackageFragment pkgFragment= (IPackageFragment) this.packageHandles.get(pkgName);
112             if (pkgFragment == null) {
113                 pkgFragment= ((PackageFragmentRoot) this.lastPkgFragmentRoot).getPackageFragment(pkgName);
114                 this.packageHandles.put(pkgName, pkgFragment);
115             }
116             IClassFile classFile= pkgFragment.getClassFile(simpleNames[length]);
117             return (Openable) classFile;
118         } else {
119             // path to a file in a directory
120
// Optimization: cache package fragment root handle and package handles
121
int rootPathLength = -1;
122             if (this.lastPkgFragmentRootPath == null
123                 || !(resourcePath.startsWith(this.lastPkgFragmentRootPath)
124                     && (rootPathLength = this.lastPkgFragmentRootPath.length()) > 0
125                     && resourcePath.charAt(rootPathLength) == '/')) {
126                 IPackageFragmentRoot root= this.getPkgFragmentRoot(resourcePath);
127                 if (root == null)
128                     return null; // match is outside classpath
129
this.lastPkgFragmentRoot = root;
130                 this.lastPkgFragmentRootPath = this.lastPkgFragmentRoot.getPath().toString();
131                 this.packageHandles = new HashtableOfArrayToObject(5);
132             }
133             // create handle
134
resourcePath = resourcePath.substring(this.lastPkgFragmentRootPath.length() + 1);
135             String JavaDoc[] simpleNames = new Path(resourcePath).segments();
136             String JavaDoc[] pkgName;
137             int length = simpleNames.length-1;
138             if (length > 0) {
139                 pkgName = new String JavaDoc[length];
140                 System.arraycopy(simpleNames, 0, pkgName, 0, length);
141             } else {
142                 pkgName = CharOperation.NO_STRINGS;
143             }
144             IPackageFragment pkgFragment= (IPackageFragment) this.packageHandles.get(pkgName);
145             if (pkgFragment == null) {
146                 pkgFragment= ((PackageFragmentRoot) this.lastPkgFragmentRoot).getPackageFragment(pkgName);
147                 this.packageHandles.put(pkgName, pkgFragment);
148             }
149             String JavaDoc simpleName= simpleNames[length];
150             if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(simpleName)) {
151                 ICompilationUnit unit= pkgFragment.getCompilationUnit(simpleName);
152                 return (Openable) unit;
153             } else {
154                 IClassFile classFile= pkgFragment.getClassFile(simpleName);
155                 return (Openable) classFile;
156             }
157         }
158     }
159     
160     /**
161      * Returns a handle denoting the class member identified by its scope.
162      */

163     public IJavaElement createElement(ClassScope scope, ICompilationUnit unit, HashSet JavaDoc existingElements, HashMap JavaDoc knownScopes) {
164         return createElement(scope, scope.referenceContext.sourceStart, unit, existingElements, knownScopes);
165     }
166     /**
167      * Create handle by adding child to parent obtained by recursing into parent scopes.
168      */

169     private IJavaElement createElement(Scope scope, int elementPosition, ICompilationUnit unit, HashSet JavaDoc existingElements, HashMap JavaDoc knownScopes) {
170         IJavaElement newElement = (IJavaElement)knownScopes.get(scope);
171         if (newElement != null) return newElement;
172     
173         switch(scope.kind) {
174             case Scope.COMPILATION_UNIT_SCOPE :
175                 newElement = unit;
176                 break;
177             case Scope.CLASS_SCOPE :
178                 IJavaElement parentElement = createElement(scope.parent, elementPosition, unit, existingElements, knownScopes);
179                 switch (parentElement.getElementType()) {
180                     case IJavaElement.COMPILATION_UNIT :
181                         newElement = ((ICompilationUnit)parentElement).getType(new String JavaDoc(scope.enclosingSourceType().sourceName));
182                         break;
183                     case IJavaElement.TYPE :
184                         newElement = ((IType)parentElement).getType(new String JavaDoc(scope.enclosingSourceType().sourceName));
185                         break;
186                     case IJavaElement.FIELD :
187                     case IJavaElement.INITIALIZER :
188                     case IJavaElement.METHOD :
189                         IMember member = (IMember)parentElement;
190                         if (member.isBinary()) {
191                             return null;
192                         } else {
193                             newElement = member.getType(new String JavaDoc(scope.enclosingSourceType().sourceName), 1);
194                             // increment occurrence count if collision is detected
195
if (newElement != null) {
196                                 while (!existingElements.add(newElement)) ((SourceRefElement)newElement).occurrenceCount++;
197                             }
198                         }
199                         break;
200                 }
201                 if (newElement != null) {
202                     knownScopes.put(scope, newElement);
203                 }
204                 break;
205             case Scope.METHOD_SCOPE :
206                 IType parentType = (IType) createElement(scope.parent, elementPosition, unit, existingElements, knownScopes);
207                 MethodScope methodScope = (MethodScope) scope;
208                 if (methodScope.isInsideInitializer()) {
209                     // inside field or initializer, must find proper one
210
TypeDeclaration type = methodScope.referenceType();
211                     int occurenceCount = 1;
212                     for (int i = 0, length = type.fields.length; i < length; i++) {
213                         FieldDeclaration field = type.fields[i];
214                         if (field.declarationSourceStart < elementPosition && field.declarationSourceEnd > elementPosition) {
215                             switch (field.getKind()) {
216                                 case AbstractVariableDeclaration.FIELD :
217                                 case AbstractVariableDeclaration.ENUM_CONSTANT :
218                                     newElement = parentType.getField(new String JavaDoc(field.name));
219                                     break;
220                                 case AbstractVariableDeclaration.INITIALIZER :
221                                     newElement = parentType.getInitializer(occurenceCount);
222                                     break;
223                             }
224                             break;
225                         } else if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
226                             occurenceCount++;
227                         }
228                     }
229                 } else {
230                     // method element
231
AbstractMethodDeclaration method = methodScope.referenceMethod();
232                     newElement = parentType.getMethod(new String JavaDoc(method.selector), Util.typeParameterSignatures(method));
233                     if (newElement != null) {
234                         knownScopes.put(scope, newElement);
235                     }
236                 }
237                 break;
238             case Scope.BLOCK_SCOPE :
239                 // standard block, no element per se
240
newElement = createElement(scope.parent, elementPosition, unit, existingElements, knownScopes);
241                 break;
242         }
243         return newElement;
244     }
245     /**
246      * Returns the package fragment root that corresponds to the given jar path.
247      * See createOpenable(...) for the format of the jar path string.
248      * If not null, uses the given scope as a hint for getting Java project handles.
249      */

250     private IPackageFragmentRoot getJarPkgFragmentRoot(String JavaDoc jarPathString, IJavaSearchScope scope) {
251
252         IPath jarPath= new Path(jarPathString);
253         
254         Object JavaDoc target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), jarPath, false);
255         if (target instanceof IFile) {
256             // internal jar: is it on the classpath of its project?
257
// e.g. org.eclipse.swt.win32/ws/win32/swt.jar
258
// is NOT on the classpath of org.eclipse.swt.win32
259
IFile jarFile = (IFile)target;
260             JavaProject javaProject = (JavaProject) this.javaModel.getJavaProject(jarFile);
261             try {
262                 IClasspathEntry entry = javaProject.getClasspathEntryFor(jarPath);
263                 if (entry != null) {
264                     return javaProject.getPackageFragmentRoot(jarFile);
265                 }
266             } catch (JavaModelException e) {
267                 // ignore and try to find another project
268
}
269         }
270         
271         // walk projects in the scope and find the first one that has the given jar path in its classpath
272
IJavaProject[] projects;
273         if (scope != null) {
274             IPath[] enclosingProjectsAndJars = scope.enclosingProjectsAndJars();
275             int length = enclosingProjectsAndJars.length;
276             projects = new IJavaProject[length];
277             int index = 0;
278             for (int i = 0; i < length; i++) {
279                 IPath path = enclosingProjectsAndJars[i];
280                 if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment())) {
281                     projects[index++] = this.javaModel.getJavaProject(path.segment(0));
282                 }
283             }
284             if (index < length) {
285                 System.arraycopy(projects, 0, projects = new IJavaProject[index], 0, index);
286             }
287             IPackageFragmentRoot root = getJarPkgFragmentRoot(jarPath, target, projects);
288             if (root != null) {
289                 return root;
290             }
291         }
292         
293         // not found in the scope, walk all projects
294
try {
295             projects = this.javaModel.getJavaProjects();
296         } catch (JavaModelException e) {
297             // java model is not accessible
298
return null;
299         }
300         return getJarPkgFragmentRoot(jarPath, target, projects);
301     }
302     
303     private IPackageFragmentRoot getJarPkgFragmentRoot(
304         IPath jarPath,
305         Object JavaDoc target,
306         IJavaProject[] projects) {
307         for (int i= 0, projectCount= projects.length; i < projectCount; i++) {
308             try {
309                 JavaProject javaProject= (JavaProject)projects[i];
310                 IClasspathEntry classpathEnty = javaProject.getClasspathEntryFor(jarPath);
311                 if (classpathEnty != null) {
312                     if (target instanceof IFile) {
313                         // internal jar
314
return javaProject.getPackageFragmentRoot((IFile)target);
315                     } else {
316                         // external jar
317
return javaProject.getPackageFragmentRoot0(jarPath);
318                     }
319                 }
320             } catch (JavaModelException e) {
321                 // JavaModelException from getResolvedClasspath - a problem occured while accessing project: nothing we can do, ignore
322
}
323         }
324         return null;
325     }
326     
327     /**
328      * Returns the package fragment root that contains the given resource path.
329      */

330     private IPackageFragmentRoot getPkgFragmentRoot(String JavaDoc pathString) {
331
332         IPath path= new Path(pathString);
333         IProject[] projects= ResourcesPlugin.getWorkspace().getRoot().getProjects();
334         for (int i= 0, max= projects.length; i < max; i++) {
335             try {
336                 IProject project = projects[i];
337                 if (!project.isAccessible()
338                     || !project.hasNature(JavaCore.NATURE_ID)) continue;
339                 IJavaProject javaProject= this.javaModel.getJavaProject(project);
340                 IPackageFragmentRoot[] roots= javaProject.getPackageFragmentRoots();
341                 for (int j= 0, rootCount= roots.length; j < rootCount; j++) {
342                     PackageFragmentRoot root= (PackageFragmentRoot)roots[j];
343                     if (root.getPath().isPrefixOf(path) && !Util.isExcluded(path, root.fullInclusionPatternChars(), root.fullExclusionPatternChars(), false)) {
344                         return root;
345                     }
346                 }
347             } catch (CoreException e) {
348                 // CoreException from hasNature - should not happen since we check that the project is accessible
349
// JavaModelException from getPackageFragmentRoots - a problem occured while accessing project: nothing we can do, ignore
350
}
351         }
352         return null;
353     }
354     
355 }
356
Popular Tags