1 12 package org.eclipse.jdt.internal.ui.wizards; 13 14 import com.ibm.icu.text.Collator; 15 16 import java.io.IOException ; 17 import java.io.InputStream ; 18 import java.util.ArrayList ; 19 import java.util.Collections ; 20 import java.util.Comparator ; 21 import java.util.HashMap ; 22 import java.util.HashSet ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import java.util.Set ; 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 63 public class ClassPathDetector implements IResourceProxyVisitor { 64 65 private HashMap fSourceFolders; 66 private List fClassFiles; 67 private HashSet 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 { 77 private Collator fCollator= Collator.getInstance(); 78 public int compare(Object o1, Object 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 (); 88 fJARFiles= new HashSet (10); 89 fClassFiles= new ArrayList (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 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 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 cpEntries= new ArrayList (); 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 iter= fSourceFolders.keySet().iterator(); 169 while (iter.hasNext()) { 170 Object key= iter.next(); 171 List cus= (List ) fSourceFolders.get(key); 172 if (cus.contains(path)) { 173 return (IPath) key; 174 } 175 } 176 return null; 177 } 178 179 private IPath detectOutputFolder(List entries) throws CoreException { 180 HashSet classFolders= new HashSet (); 181 182 for (Iterator iter= fClassFiles.iterator(); iter.hasNext();) { 183 IFile file= (IFile) iter.next(); 184 IClassFileReader reader= null; 185 InputStream 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 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; } 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 (className, 0, idx)); 208 IPath cuPath= relPath.append(new String (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 cpEntries, IPath outputLocation) { 243 ArrayList res= new ArrayList (); 244 Set sourceFolderSet= fSourceFolders.keySet(); 245 for (Iterator 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 resEntries) { 262 ArrayList res= new ArrayList (); 263 Set sourceFolderSet= fSourceFolders.keySet(); 264 for (Iterator iter= sourceFolderSet.iterator(); iter.hasNext();) { 265 IPath path= (IPath) iter.next(); 266 ArrayList excluded= new ArrayList (); 267 for (Iterator 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 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 } catch (InvalidInputException e) { 302 } 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 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 (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 map, IPath folderPath, IPath relPath) { 338 List list= (List ) map.get(folderPath); 339 if (list == null) { 340 list= new ArrayList (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 name, String ext) { 358 return name.endsWith(ext) && (ext.length() != name.length()); 359 } 360 361 private boolean isValidCUName(String name) { 362 return !JavaConventions.validateCompilationUnitName(name).matches(IStatus.ERROR); 363 } 364 365 368 public boolean visit(IResourceProxy proxy) { 369 if (fMonitor.isCanceled()) { 370 throw new OperationCanceledException(); 371 } 372 373 if (proxy.getType() == IResource.FILE) { 374 String name= proxy.getName(); 375 if (isValidCUName(name)) { 376 visitCompilationUnit((IFile) proxy.requestResource()); 377 } else if (hasExtension(name, ".class")) { fClassFiles.add(proxy.requestResource()); 379 } else if (hasExtension(name, ".jar")) { 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 |