KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > wizards > ClassPathDetector


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  * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.ui.wizards;
13
14 import com.ibm.icu.text.Collator;
15
16 import java.io.IOException JavaDoc;
17 import java.io.InputStream JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.Comparator JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IPath;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.NullProgressMonitor;
32 import org.eclipse.core.runtime.OperationCanceledException;
33 import org.eclipse.core.runtime.Path;
34 import org.eclipse.core.runtime.Status;
35
36 import org.eclipse.core.resources.IFile;
37 import org.eclipse.core.resources.IProject;
38 import org.eclipse.core.resources.IResource;
39 import org.eclipse.core.resources.IResourceProxy;
40 import org.eclipse.core.resources.IResourceProxyVisitor;
41
42 import org.eclipse.jdt.core.IClasspathEntry;
43 import org.eclipse.jdt.core.ICompilationUnit;
44 import org.eclipse.jdt.core.JavaConventions;
45 import org.eclipse.jdt.core.JavaCore;
46 import org.eclipse.jdt.core.JavaModelException;
47 import org.eclipse.jdt.core.ToolFactory;
48 import org.eclipse.jdt.core.compiler.CharOperation;
49 import org.eclipse.jdt.core.compiler.IScanner;
50 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
51 import org.eclipse.jdt.core.compiler.InvalidInputException;
52 import org.eclipse.jdt.core.util.IClassFileReader;
53 import org.eclipse.jdt.core.util.ISourceAttribute;
54
55 import org.eclipse.jdt.internal.corext.util.Messages;
56
57 import org.eclipse.jdt.ui.PreferenceConstants;
58
59 import org.eclipse.jdt.internal.ui.JavaPlugin;
60
61 /**
62   */

63 public class ClassPathDetector implements IResourceProxyVisitor {
64         
65     private HashMap JavaDoc fSourceFolders;
66     private List JavaDoc fClassFiles;
67     private HashSet JavaDoc fJARFiles;
68         
69     private IProject fProject;
70         
71     private IPath fResultOutputFolder;
72     private IClasspathEntry[] fResultClasspath;
73     
74     private IProgressMonitor fMonitor;
75     
76     private static class CPSorter implements Comparator JavaDoc {
77         private Collator fCollator= Collator.getInstance();
78         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
79             IClasspathEntry e1= (IClasspathEntry) o1;
80             IClasspathEntry e2= (IClasspathEntry) o2;
81             return fCollator.compare(e1.getPath().toString(), e2.getPath().toString());
82         }
83     }
84     
85     
86     public ClassPathDetector(IProject project, IProgressMonitor monitor) throws CoreException {
87         fSourceFolders= new HashMap JavaDoc();
88         fJARFiles= new HashSet JavaDoc(10);
89         fClassFiles= new ArrayList JavaDoc(100);
90         fProject= project;
91             
92         fResultClasspath= null;
93         fResultOutputFolder= null;
94         
95         if (monitor == null) {
96             monitor = new NullProgressMonitor();
97         }
98             
99         detectClasspath(monitor);
100     }
101     
102     
103     private boolean isNested(IPath path, Iterator JavaDoc iter) {
104         while (iter.hasNext()) {
105             IPath other= (IPath) iter.next();
106             if (other.isPrefixOf(path)) {
107                 return true;
108             }
109         }
110         return false;
111     }
112     
113     /**
114      * Method detectClasspath.
115      * @param monitor The progress monitor (not null)
116      * @throws CoreException
117      */

118     private void detectClasspath(IProgressMonitor monitor) throws CoreException {
119         try {
120             monitor.beginTask(NewWizardMessages.ClassPathDetector_operation_description, 4);
121             
122             fMonitor= monitor;
123             fProject.accept(this, IResource.NONE);
124             monitor.worked(1);
125             
126             ArrayList JavaDoc cpEntries= new ArrayList JavaDoc();
127
128             detectSourceFolders(cpEntries);
129             if (monitor.isCanceled()) {
130                 throw new OperationCanceledException();
131             }
132             monitor.worked(1);
133             
134             
135             IPath outputLocation= detectOutputFolder(cpEntries);
136             if (monitor.isCanceled()) {
137                 throw new OperationCanceledException();
138             }
139             monitor.worked(1);
140
141             detectLibraries(cpEntries, outputLocation);
142             if (monitor.isCanceled()) {
143                 throw new OperationCanceledException();
144             }
145             monitor.worked(1);
146
147             if (cpEntries.isEmpty() && fClassFiles.isEmpty()) {
148                 return;
149             }
150             IClasspathEntry[] jreEntries= PreferenceConstants.getDefaultJRELibrary();
151             for (int i= 0; i < jreEntries.length; i++) {
152                 cpEntries.add(jreEntries[i]);
153             }
154
155             IClasspathEntry[] entries= (IClasspathEntry[]) cpEntries.toArray(new IClasspathEntry[cpEntries.size()]);
156             if (!JavaConventions.validateClasspath(JavaCore.create(fProject), entries, outputLocation).isOK()) {
157                 return;
158             }
159
160             fResultClasspath= entries;
161             fResultOutputFolder= outputLocation;
162         } finally {
163             monitor.done();
164         }
165     }
166     
167     private IPath findInSourceFolders(IPath path) {
168         Iterator JavaDoc iter= fSourceFolders.keySet().iterator();
169         while (iter.hasNext()) {
170             Object JavaDoc key= iter.next();
171             List JavaDoc cus= (List JavaDoc) fSourceFolders.get(key);
172             if (cus.contains(path)) {
173                 return (IPath) key;
174             }
175         }
176         return null;
177     }
178     
179     private IPath detectOutputFolder(List JavaDoc entries) throws CoreException {
180         HashSet JavaDoc classFolders= new HashSet JavaDoc();
181         
182         for (Iterator JavaDoc iter= fClassFiles.iterator(); iter.hasNext();) {
183             IFile file= (IFile) iter.next();
184             IClassFileReader reader= null;
185             InputStream JavaDoc content= null;
186             try {
187                 content= file.getContents();
188                 reader= ToolFactory.createDefaultClassFileReader(content, IClassFileReader.CLASSFILE_ATTRIBUTES);
189             } finally {
190                 try {
191                     if (content != null)
192                         content.close();
193                 } catch (IOException JavaDoc e) {
194                     throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
195                         Messages.format(NewWizardMessages.ClassPathDetector_error_closing_file, file.getFullPath().toString()),
196                         e));
197                 }
198             }
199             if (reader == null) {
200                 continue; // problematic class file
201
}
202             char[] className= reader.getClassName();
203             ISourceAttribute sourceAttribute= reader.getSourceFileAttribute();
204             if (className != null && sourceAttribute != null && sourceAttribute.getSourceFileName() != null) {
205                 IPath packPath= file.getParent().getFullPath();
206                 int idx= CharOperation.lastIndexOf('/', className) + 1;
207                 IPath relPath= new Path(new String JavaDoc(className, 0, idx));
208                 IPath cuPath= relPath.append(new String JavaDoc(sourceAttribute.getSourceFileName()));
209                 
210                 IPath resPath= null;
211                 if (idx == 0) {
212                     resPath= packPath;
213                 } else {
214                     IPath folderPath= getFolderPath(packPath, relPath);
215                     if (folderPath != null) {
216                         resPath= folderPath;
217                     }
218                 }
219                 if (resPath != null) {
220                     IPath path= findInSourceFolders(cuPath);
221                     if (path != null) {
222                         return resPath;
223                     } else {
224                         classFolders.add(resPath);
225                     }
226                 }
227             }
228         }
229         IPath projPath= fProject.getFullPath();
230         if (fSourceFolders.size() == 1 && classFolders.isEmpty() && fSourceFolders.get(projPath) != null) {
231             return projPath;
232         } else {
233             IPath path= projPath.append(PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_BINNAME));
234             while (classFolders.contains(path)) {
235                 path= new Path(path.toString() + '1');
236             }
237             return path;
238         }
239     }
240
241
242     private void detectLibraries(ArrayList JavaDoc cpEntries, IPath outputLocation) {
243         ArrayList JavaDoc res= new ArrayList JavaDoc();
244         Set JavaDoc sourceFolderSet= fSourceFolders.keySet();
245         for (Iterator JavaDoc iter= fJARFiles.iterator(); iter.hasNext();) {
246             IPath path= (IPath) iter.next();
247             if (isNested(path, sourceFolderSet.iterator())) {
248                 continue;
249             }
250             if (outputLocation != null && outputLocation.isPrefixOf(path)) {
251                 continue;
252             }
253             IClasspathEntry entry= JavaCore.newLibraryEntry(path, null, null);
254             res.add(entry);
255         }
256         Collections.sort(res, new CPSorter());
257         cpEntries.addAll(res);
258     }
259
260
261     private void detectSourceFolders(ArrayList JavaDoc resEntries) {
262         ArrayList JavaDoc res= new ArrayList JavaDoc();
263         Set JavaDoc sourceFolderSet= fSourceFolders.keySet();
264         for (Iterator JavaDoc iter= sourceFolderSet.iterator(); iter.hasNext();) {
265             IPath path= (IPath) iter.next();
266             ArrayList JavaDoc excluded= new ArrayList JavaDoc();
267             for (Iterator JavaDoc inner= sourceFolderSet.iterator(); inner.hasNext();) {
268                 IPath other= (IPath) inner.next();
269                 if (!path.equals(other) && path.isPrefixOf(other)) {
270                     IPath pathToExclude= other.removeFirstSegments(path.segmentCount()).addTrailingSeparator();
271                     excluded.add(pathToExclude);
272                 }
273             }
274             IPath[] excludedPaths= (IPath[]) excluded.toArray(new IPath[excluded.size()]);
275             IClasspathEntry entry= JavaCore.newSourceEntry(path, excludedPaths);
276             res.add(entry);
277         }
278         Collections.sort(res, new CPSorter());
279         resEntries.addAll(res);
280     }
281
282     private void visitCompilationUnit(IFile file) {
283         ICompilationUnit cu= JavaCore.createCompilationUnitFrom(file);
284         if (cu != null) {
285             ICompilationUnit workingCopy= null;
286             try {
287                 workingCopy= cu.getWorkingCopy(null);
288                 IPath relPath= getPackagePath(workingCopy.getSource());
289                 IPath packPath= file.getParent().getFullPath();
290                 String JavaDoc cuName= file.getName();
291                 if (relPath == null) {
292                     addToMap(fSourceFolders, packPath, new Path(cuName));
293                 } else {
294                     IPath folderPath= getFolderPath(packPath, relPath);
295                     if (folderPath != null) {
296                         addToMap(fSourceFolders, folderPath, relPath.append(cuName));
297                     }
298                 }
299             } catch (JavaModelException e) {
300                 // ignore
301
} catch (InvalidInputException e) {
302                 // ignore
303
} finally {
304                 if (workingCopy != null) {
305                     try {
306                         workingCopy.discardWorkingCopy();
307                     } catch (JavaModelException ignore) {
308                     }
309                 }
310             }
311         }
312     }
313     
314     private IPath getPackagePath(String JavaDoc source) throws InvalidInputException {
315         IScanner scanner= ToolFactory.createScanner(false, false, false, false);
316         scanner.setSource(source.toCharArray());
317         scanner.resetTo(0, source.length() - 1);
318         int tok= scanner.getNextToken();
319         if (tok != ITerminalSymbols.TokenNamepackage) {
320             return null;
321         }
322         IPath res= Path.EMPTY;
323         do {
324             tok= scanner.getNextToken();
325             if (tok == ITerminalSymbols.TokenNameIdentifier) {
326                 res= res.append(new String JavaDoc(scanner.getCurrentTokenSource()));
327             } else {
328                 return res;
329             }
330             tok= scanner.getNextToken();
331         } while (tok == ITerminalSymbols.TokenNameDOT);
332         
333         return res;
334     }
335     
336     
337     private void addToMap(HashMap JavaDoc map, IPath folderPath, IPath relPath) {
338         List JavaDoc list= (List JavaDoc) map.get(folderPath);
339         if (list == null) {
340             list= new ArrayList JavaDoc(50);
341             map.put(folderPath, list);
342         }
343         list.add(relPath);
344     }
345
346     private IPath getFolderPath(IPath packPath, IPath relpath) {
347         int remainingSegments= packPath.segmentCount() - relpath.segmentCount();
348         if (remainingSegments >= 0) {
349             IPath common= packPath.removeFirstSegments(remainingSegments);
350             if (common.equals(relpath)) {
351                 return packPath.uptoSegment(remainingSegments);
352             }
353         }
354         return null;
355     }
356
357     private boolean hasExtension(String JavaDoc name, String JavaDoc ext) {
358         return name.endsWith(ext) && (ext.length() != name.length());
359     }
360     
361     private boolean isValidCUName(String JavaDoc name) {
362         return !JavaConventions.validateCompilationUnitName(name).matches(IStatus.ERROR);
363     }
364
365     /* (non-Javadoc)
366      * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy)
367      */

368     public boolean visit(IResourceProxy proxy) {
369         if (fMonitor.isCanceled()) {
370             throw new OperationCanceledException();
371         }
372         
373         if (proxy.getType() == IResource.FILE) {
374             String JavaDoc name= proxy.getName();
375             if (isValidCUName(name)) {
376                 visitCompilationUnit((IFile) proxy.requestResource());
377             } else if (hasExtension(name, ".class")) { //$NON-NLS-1$
378
fClassFiles.add(proxy.requestResource());
379             } else if (hasExtension(name, ".jar")) { //$NON-NLS-1$
380
fJARFiles.add(proxy.requestFullPath());
381             }
382             return false;
383         }
384         return true;
385     }
386
387
388     public IPath getOutputLocation() {
389         return fResultOutputFolder;
390     }
391         
392     public IClasspathEntry[] getClasspath() {
393         if (fResultClasspath == null)
394             return new IClasspathEntry[0];
395         return fResultClasspath;
396     }
397 }
398
Popular Tags