1 /******************************************************************************* 2 * Copyright (c) 2000, 2003 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package net.sourceforge.phpdt.internal.core; 12 13 import java.io.BufferedInputStream; 14 import java.io.BufferedOutputStream; 15 import java.io.ByteArrayInputStream; 16 import java.io.ByteArrayOutputStream; 17 import java.io.File; 18 import java.io.FileInputStream; 19 import java.io.FileOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.OutputStream; 23 import java.io.OutputStreamWriter; 24 import java.io.StringReader; 25 import java.util.ArrayList; 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.Hashtable; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.Map; 32 33 import javax.xml.parsers.DocumentBuilder; 34 import javax.xml.parsers.DocumentBuilderFactory; 35 import javax.xml.parsers.ParserConfigurationException; 36 import javax.xml.parsers.SAXParserFactory; 37 38 import net.sourceforge.phpdt.core.IClasspathEntry; 39 import net.sourceforge.phpdt.core.ICompilationUnit; 40 import net.sourceforge.phpdt.core.IJavaElement; 41 import net.sourceforge.phpdt.core.IJavaModelMarker; 42 import net.sourceforge.phpdt.core.IJavaModelStatus; 43 import net.sourceforge.phpdt.core.IJavaModelStatusConstants; 44 import net.sourceforge.phpdt.core.IJavaProject; 45 import net.sourceforge.phpdt.core.IPackageFragment; 46 import net.sourceforge.phpdt.core.IPackageFragmentRoot; 47 import net.sourceforge.phpdt.core.JavaCore; 48 import net.sourceforge.phpdt.core.JavaModelException; 49 import net.sourceforge.phpdt.core.WorkingCopyOwner; 50 import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment; 51 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; 52 import net.sourceforge.phpdt.internal.core.util.MementoTokenizer; 53 import net.sourceforge.phpdt.internal.core.util.Util; 54 import net.sourceforge.phpdt.internal.corext.Assert; 55 import net.sourceforge.phpeclipse.LoadPathEntry; 56 import net.sourceforge.phpeclipse.PHPeclipsePlugin; 57 58 import org.eclipse.core.resources.ICommand; 59 import org.eclipse.core.resources.IFile; 60 import org.eclipse.core.resources.IFolder; 61 import org.eclipse.core.resources.IMarker; 62 import org.eclipse.core.resources.IProject; 63 import org.eclipse.core.resources.IProjectDescription; 64 import org.eclipse.core.resources.IProjectNature; 65 import org.eclipse.core.resources.IResource; 66 import org.eclipse.core.resources.IWorkspace; 67 import org.eclipse.core.resources.IWorkspaceRoot; 68 import org.eclipse.core.resources.ResourcesPlugin; 69 import org.eclipse.core.runtime.CoreException; 70 import org.eclipse.core.runtime.IPath; 71 import org.eclipse.core.runtime.IProgressMonitor; 72 import org.eclipse.core.runtime.Path; 73 import org.eclipse.core.runtime.Preferences; 74 import org.eclipse.core.runtime.QualifiedName; 75 import org.w3c.dom.Element; 76 import org.w3c.dom.Node; 77 import org.w3c.dom.NodeList; 78 import org.xml.sax.Attributes; 79 import org.xml.sax.ContentHandler; 80 import org.xml.sax.InputSource; 81 import org.xml.sax.Locator; 82 import org.xml.sax.SAXException; 83 import org.xml.sax.XMLReader; 84 85 /** 86 * Handle for a Java Project. 87 * 88 * <p> 89 * A Java Project internally maintains a devpath that corresponds to the 90 * project's classpath. The classpath may include source folders from the 91 * current project; jars in the current project, other projects, and the local 92 * file system; and binary folders (output location) of other projects. The Java 93 * Model presents source elements corresponding to output .class files in other 94 * projects, and thus uses the devpath rather than the classpath (which is 95 * really a compilation path). The devpath mimics the classpath, except has 96 * source folder entries in place of output locations in external projects. 97 * 98 * <p> 99 * Each JavaProject has a NameLookup facility that locates elements on by name, 100 * based on the devpath. 101 * 102 * @see IJavaProject 103 */ 104 public class JavaProject extends Openable implements IJavaProject, 105 IProjectNature { 106 107 /** 108 * Whether the underlying file system is case sensitive. 109 */ 110 protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$ 111 112 /** 113 * An empty array of strings indicating that a project doesn't have any 114 * prerequesite projects. 115 */ 116 protected static final String[] NO_PREREQUISITES = new String[0]; 117 118 /** 119 * The platform project this <code>IJavaProject</code> is based on 120 */ 121 protected IProject project; 122 123 protected List fLoadPathEntries; 124 125 protected boolean fScratched; 126 127 /** 128 * Name of file containing project classpath 129 */ 130 public static final String CLASSPATH_FILENAME = ".classpath"; //$NON-NLS-1$ 131 132 /** 133 * Name of file containing custom project preferences 134 */ 135 public static final String PREF_FILENAME = ".jprefs"; //$NON-NLS-1$ 136 137 /** 138 * Value of the project's raw classpath if the .classpath file contains 139 * invalid entries. 140 */ 141 public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0]; 142 143 private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$ 144 145 /* 146 * Value of project's resolved classpath while it is being resolved 147 */ 148 private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0]; 149 150 /** 151 * Returns a canonicalized path from the given external path. Note that the 152 * return path contains the same number of segments and it contains a device 153 * only if the given path contained one. 154 * 155 * @see java.io.File for the definition of a canonicalized path 156 */ canonicalizedPath(IPath externalPath)157 public static IPath canonicalizedPath(IPath externalPath) { 158 159 if (externalPath == null) 160 return null; 161 162 if (JavaModelManager.VERBOSE) { 163 System.out 164 .println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$ 165 } 166 167 if (IS_CASE_SENSITIVE) { 168 if (JavaModelManager.VERBOSE) { 169 System.out 170 .println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$ 171 } 172 return externalPath; 173 } 174 175 // if not external path, return original path 176 IWorkspace workspace = ResourcesPlugin.getWorkspace(); 177 if (workspace == null) 178 return externalPath; // protection during shutdown (30487) 179 if (workspace.getRoot().findMember(externalPath) != null) { 180 if (JavaModelManager.VERBOSE) { 181 System.out 182 .println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$ 183 } 184 return externalPath; 185 } 186 187 IPath canonicalPath = null; 188 try { 189 canonicalPath = new Path(new File(externalPath.toOSString()) 190 .getCanonicalPath()); 191 } catch (IOException e) { 192 // default to original path 193 if (JavaModelManager.VERBOSE) { 194 System.out 195 .println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$ 196 } 197 return externalPath; 198 } 199 200 IPath result; 201 int canonicalLength = canonicalPath.segmentCount(); 202 if (canonicalLength == 0) { 203 // the java.io.File canonicalization failed 204 if (JavaModelManager.VERBOSE) { 205 System.out 206 .println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$ 207 } 208 return externalPath; 209 } else if (externalPath.isAbsolute()) { 210 result = canonicalPath; 211 } else { 212 // if path is relative, remove the first segments that were added by 213 // the java.io.File canonicalization 214 // e.g. 'lib/classes.zip' was converted to 215 // 'd:/myfolder/lib/classes.zip' 216 int externalLength = externalPath.segmentCount(); 217 if (canonicalLength >= externalLength) { 218 result = canonicalPath.removeFirstSegments(canonicalLength 219 - externalLength); 220 } else { 221 if (JavaModelManager.VERBOSE) { 222 System.out 223 .println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 224 } 225 return externalPath; 226 } 227 } 228 229 // keep device only if it was specified (this is because 230 // File.getCanonicalPath() converts '/lib/classed.zip' to 231 // 'd:/lib/classes/zip') 232 if (externalPath.getDevice() == null) { 233 result = result.setDevice(null); 234 } 235 if (JavaModelManager.VERBOSE) { 236 System.out 237 .println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$ 238 } 239 return result; 240 } 241 242 /** 243 * Constructor needed for <code>IProject.getNature()</code> and 244 * <code>IProject.addNature()</code>. 245 * 246 * @see #setProject(IProject) 247 */ JavaProject()248 public JavaProject() { 249 super(null, null); 250 } 251 JavaProject(IProject project, JavaElement parent)252 public JavaProject(IProject project, JavaElement parent) { 253 super(parent, project.getName()); 254 this.project = project; 255 } 256 addLoadPathEntry(IProject anotherPHPProject)257 public void addLoadPathEntry(IProject anotherPHPProject) { 258 fScratched = true; 259 260 LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject); 261 getLoadPathEntries().add(newEntry); 262 } 263 configure()264 public void configure() throws CoreException { 265 // get project description and then the associated build commands 266 IProjectDescription desc = project.getDescription(); 267 ICommand[] commands = desc.getBuildSpec(); 268 269 // determine if builder already associated 270 boolean found = false; 271 for (int i = 0; i < commands.length; ++i) { 272 if (commands[i].getBuilderName().equals( 273 PHPeclipsePlugin.BUILDER_PARSER_ID)) { 274 found = true; 275 break; 276 } 277 } 278 279 // add builder if not already in project 280 if (!found) { 281 ICommand command = desc.newCommand(); 282 command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID); 283 ICommand[] newCommands = new ICommand[commands.length + 1]; 284 285 // Add it before other builders. 286 System.arraycopy(commands, 0, newCommands, 1, commands.length); 287 newCommands[0] = command; 288 desc.setBuildSpec(newCommands); 289 project.setDescription(desc, null); 290 } 291 } 292 loadLoadPathEntries()293 protected void loadLoadPathEntries() { 294 fLoadPathEntries = new ArrayList(); 295 296 IFile loadPathsFile = getLoadPathEntriesFile(); 297 298 XMLReader reader = null; 299 try { 300 reader = SAXParserFactory.newInstance().newSAXParser() 301 .getXMLReader(); 302 reader.setContentHandler(getLoadPathEntriesContentHandler()); 303 reader.parse(new InputSource(loadPathsFile.getContents())); 304 } catch (Exception e) { 305 // the file is nonextant or unreadable 306 } 307 } 308 getLoadPathEntries()309 public List getLoadPathEntries() { 310 if (fLoadPathEntries == null) { 311 loadLoadPathEntries(); 312 } 313 314 return fLoadPathEntries; 315 } 316 getLoadPathEntriesContentHandler()317 protected ContentHandler getLoadPathEntriesContentHandler() { 318 return new ContentHandler() { 319 public void characters(char[] arg0, int arg1, int arg2) 320 throws SAXException { 321 } 322 323 public void endDocument() throws SAXException { 324 } 325 326 public void endElement(String arg0, String arg1, String arg2) 327 throws SAXException { 328 } 329 330 public void endPrefixMapping(String arg0) throws SAXException { 331 } 332 333 public void ignorableWhitespace(char[] arg0, int arg1, int arg2) 334 throws SAXException { 335 } 336 337 public void processingInstruction(String arg0, String arg1) 338 throws SAXException { 339 } 340 341 public void setDocumentLocator(Locator arg0) { 342 } 343 344 public void skippedEntity(String arg0) throws SAXException { 345 } 346 347 public void startDocument() throws SAXException { 348 } 349 350 public void startElement(String namespaceURI, String localName, 351 String qName, Attributes atts) throws SAXException { 352 if ("pathentry".equals(qName)) 353 if ("project".equals(atts.getValue("type"))) { 354 IPath referencedProjectPath = new Path(atts 355 .getValue("path")); 356 IProject referencedProject = getProject(referencedProjectPath 357 .lastSegment()); 358 fLoadPathEntries.add(new LoadPathEntry( 359 referencedProject)); 360 } 361 } 362 363 public void startPrefixMapping(String arg0, String arg1) 364 throws SAXException { 365 } 366 }; 367 } 368 369 protected IFile getLoadPathEntriesFile() { 370 return project.getFile(".loadpath"); 371 } 372 373 protected String getLoadPathXML() { 374 StringBuffer buffer = new StringBuffer(); 375 buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>"); 376 377 Iterator pathEntriesIterator = fLoadPathEntries.iterator(); 378 379 while (pathEntriesIterator.hasNext()) { 380 LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next(); 381 buffer.append(entry.toXML()); 382 } 383 384 buffer.append("</loadpath>"); 385 return buffer.toString(); 386 } 387 388 /** 389 * Adds a builder to the build spec for the given project. 390 */ 391 protected void addToBuildSpec(String builderID) throws CoreException { 392 393 IProjectDescription description = getProject().getDescription(); 394 ICommand javaCommand = getJavaCommand(description); 395 396 if (javaCommand == null) { 397 398 // Add a Java command to the build spec 399 ICommand command = description.newCommand(); 400 command.setBuilderName(builderID); 401 setJavaCommand(description, command); 402 } 403 } 404 405 /** 406 * @see Openable 407 */ 408 protected boolean buildStructure(OpenableElementInfo info, 409 IProgressMonitor pm, Map newElements, IResource underlyingResource) 410 throws JavaModelException { 411 412 // check whether the java project can be opened 413 if (!underlyingResource.isAccessible()) { 414 throw newNotPresentException(); 415 } 416 417 IWorkspace workspace = ResourcesPlugin.getWorkspace(); 418 IWorkspaceRoot wRoot = workspace.getRoot(); 419 // cannot refresh cp markers on opening (emulate cp check on startup) 420 // since can create deadlocks (see bug 37274) 421 // IClasspathEntry[] resolvedClasspath = 422 // getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't 423 // generateMarkerOnError*/, false/*don't returnResolutionInProgress*/); 424 425 // // compute the pkg fragment roots 426 // info.setChildren(computePackageFragmentRoots(resolvedClasspath, 427 // false)); 428 // 429 // // remember the timestamps of external libraries the first time they 430 // are looked up 431 // for (int i = 0, length = resolvedClasspath.length; i < length; i++) { 432 // IClasspathEntry entry = resolvedClasspath[i]; 433 // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { 434 // IPath path = entry.getPath(); 435 // Object target = JavaModel.getTarget(wRoot, path, true); 436 // if (target instanceof java.io.File) { 437 // Map externalTimeStamps = 438 // JavaModelManager.getJavaModelManager().deltaState.externalTimeStamps; 439 // if (externalTimeStamps.get(path) == null) { 440 // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target); 441 // externalTimeStamps.put(path, new Long(timestamp)); 442 // } 443 // } 444 // } 445 // } 446 447 return true; 448 } 449 450 protected void closing(Object info) { 451 452 // // forget source attachment recommendations 453 // Object[] children = ((JavaElementInfo)info).children; 454 // for (int i = 0, length = children.length; i < length; i++) { 455 // Object child = children[i]; 456 // if (child instanceof JarPackageFragmentRoot){ 457 // ((JarPackageFragmentRoot)child).setSourceAttachmentProperty(null); 458 // } 459 // } 460 461 super.closing(info); 462 } 463 464 // protected void closing(Object info) throws JavaModelException { 465 // 466 // // forget source attachment recommendations 467 // IPackageFragmentRoot[] roots = this.getPackageFragmentRoots(); 468 // // for (int i = 0; i < roots.length; i++) { 469 // // if (roots[i] instanceof JarPackageFragmentRoot){ 470 // // ((JarPackageFragmentRoot) roots[i]).setSourceAttachmentProperty(null); 471 // // } 472 // // } 473 // 474 // super.closing(info); 475 // } 476 477 /** 478 * Internal computation of an expanded classpath. It will eliminate 479 * duplicates, and produce copies of exported classpath entries to avoid 480 * possible side-effects ever after. 481 */ 482 private void computeExpandedClasspath(JavaProject initialProject, 483 boolean ignoreUnresolvedVariable, boolean generateMarkerOnError, 484 HashSet rootIDs, ObjectVector accumulatedEntries, 485 Map preferredClasspaths, Map preferredOutputs) 486 throws JavaModelException { 487 488 String projectRootId = this.rootID(); 489 if (rootIDs.contains(projectRootId)) { 490 return; // break cycles if any 491 } 492 rootIDs.add(projectRootId); 493 494 IClasspathEntry[] preferredClasspath = preferredClasspaths != null ? (IClasspathEntry[]) preferredClasspaths 495 .get(this) 496 : null; 497 IPath preferredOutput = preferredOutputs != null ? (IPath) preferredOutputs 498 .get(this) 499 : null; 500 IClasspathEntry[] immediateClasspath = preferredClasspath != null ? getResolvedClasspath( 501 preferredClasspath, preferredOutput, ignoreUnresolvedVariable, 502 generateMarkerOnError, null) 503 : getResolvedClasspath(ignoreUnresolvedVariable, 504 generateMarkerOnError, false/* 505 * don't 506 * returnResolutionInProgress 507 */); 508 509 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); 510 boolean isInitialProject = this.equals(initialProject); 511 for (int i = 0, length = immediateClasspath.length; i < length; i++) { 512 ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i]; 513 if (isInitialProject || entry.isExported()) { 514 String rootID = entry.rootID(); 515 if (rootIDs.contains(rootID)) { 516 continue; 517 } 518 519 accumulatedEntries.add(entry); 520 521 // recurse in project to get all its indirect exports (only 522 // consider exported entries from there on) 523 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { 524 IResource member = workspaceRoot 525 .findMember(entry.getPath()); 526 if (member != null && member.getType() == IResource.PROJECT) { // double 527 // check 528 // if 529 // bound 530 // to 531 // project 532 // (23977) 533 IProject projRsc = (IProject) member; 534 if (JavaProject.hasJavaNature(projRsc)) { 535 JavaProject javaProject = (JavaProject) JavaCore 536 .create(projRsc); 537 javaProject 538 .computeExpandedClasspath( 539 initialProject, 540 ignoreUnresolvedVariable, 541 false /* 542 * no marker when recursing 543 * in prereq 544 */, 545 rootIDs, accumulatedEntries, 546 preferredClasspaths, 547 preferredOutputs); 548 } 549 } 550 } else { 551 rootIDs.add(rootID); 552 } 553 } 554 } 555 } 556 557 /** 558 * Internal computation of an expanded classpath. It will eliminate 559 * duplicates, and produce copies of exported classpath entries to avoid 560 * possible side-effects ever after. 561 */ 562 // private void computeExpandedClasspath( 563 // JavaProject initialProject, 564 // boolean ignoreUnresolvedVariable, 565 // boolean generateMarkerOnError, 566 // HashSet visitedProjects, 567 // ObjectVector accumulatedEntries) throws JavaModelException { 568 // 569 // if (visitedProjects.contains(this)){ 570 // return; // break cycles if any 571 // } 572 // visitedProjects.add(this); 573 // 574 // if (generateMarkerOnError && !this.equals(initialProject)){ 575 // generateMarkerOnError = false; 576 // } 577 // IClasspathEntry[] immediateClasspath = 578 // getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError); 579 // 580 // IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); 581 // for (int i = 0, length = immediateClasspath.length; i < length; i++){ 582 // IClasspathEntry entry = immediateClasspath[i]; 583 // 584 // boolean isInitialProject = this.equals(initialProject); 585 // if (isInitialProject || entry.isExported()){ 586 // 587 // accumulatedEntries.add(entry); 588 // 589 // // recurse in project to get all its indirect exports (only consider 590 // exported entries from there on) 591 // if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) { 592 // IResource member = workspaceRoot.findMember(entry.getPath()); 593 // if (member != null && member.getType() == IResource.PROJECT){ // double 594 // check if bound to project (23977) 595 // IProject projRsc = (IProject) member; 596 // if (JavaProject.hasJavaNature(projRsc)) { 597 // JavaProject project = (JavaProject) JavaCore.create(projRsc); 598 // project.computeExpandedClasspath( 599 // initialProject, 600 // ignoreUnresolvedVariable, 601 // generateMarkerOnError, 602 // visitedProjects, 603 // accumulatedEntries); 604 // } 605 // } 606 // } 607 // } 608 // } 609 // } 610 /** 611 * Returns (local/all) the package fragment roots identified by the given 612 * project's classpath. Note: this follows project classpath references to 613 * find required project contributions, eliminating duplicates silently. 614 * Only works with resolved entries 615 */ 616 public IPackageFragmentRoot[] computePackageFragmentRoots( 617 IClasspathEntry[] resolvedClasspath, boolean retrieveExportedRoots) 618 throws JavaModelException { 619 620 ObjectVector accumulatedRoots = new ObjectVector(); 621 computePackageFragmentRoots(resolvedClasspath, accumulatedRoots, 622 new HashSet(5), // rootIDs 623 true, // inside original project 624 true, // check existency 625 retrieveExportedRoots); 626 IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots 627 .size()]; 628 accumulatedRoots.copyInto(rootArray); 629 return rootArray; 630 } 631 632 /** 633 * Computes the package fragment roots identified by the given entry. Only 634 * works with resolved entry 635 */ 636 public IPackageFragmentRoot[] computePackageFragmentRoots( 637 IClasspathEntry resolvedEntry) { 638 try { 639 return computePackageFragmentRoots( 640 new IClasspathEntry[] { resolvedEntry }, false // don't 641 // retrieve 642 // exported 643 // roots 644 ); 645 } catch (JavaModelException e) { 646 return new IPackageFragmentRoot[] {}; 647 } 648 } 649 650 /** 651 * Returns the package fragment roots identified by the given entry. In case 652 * it refers to a project, it will follow its classpath so as to find 653 * exported roots as well. Only works with resolved entry 654 */ 655 public void computePackageFragmentRoots(IClasspathEntry resolvedEntry, 656 ObjectVector accumulatedRoots, HashSet rootIDs, 657 boolean insideOriginalProject, boolean checkExistency, 658 boolean retrieveExportedRoots) throws JavaModelException { 659 660 String rootID = ((ClasspathEntry) resolvedEntry).rootID(); 661 if (rootIDs.contains(rootID)) 662 return; 663 664 IPath projectPath = getProject().getFullPath(); 665 IPath entryPath = resolvedEntry.getPath(); 666 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); 667 668 switch (resolvedEntry.getEntryKind()) { 669 670 // source folder 671 case IClasspathEntry.CPE_SOURCE: 672 673 if (projectPath.isPrefixOf(entryPath)) { 674 if (checkExistency) { 675 Object target = JavaModel.getTarget(workspaceRoot, 676 entryPath, checkExistency); 677 if (target == null) 678 return; 679 680 if (target instanceof IFolder || target instanceof IProject) { 681 accumulatedRoots 682 .add(getPackageFragmentRoot((IResource) target)); 683 rootIDs.add(rootID); 684 } 685 } else { 686 IPackageFragmentRoot root = getFolderPackageFragmentRoot(entryPath); 687 if (root != null) { 688 accumulatedRoots.add(root); 689 rootIDs.add(rootID); 690 } 691 } 692 } 693 break; 694 695 // internal/external JAR or folder 696 case IClasspathEntry.CPE_LIBRARY: 697 698 if (!insideOriginalProject && !resolvedEntry.isExported()) 699 return; 700 701 if (checkExistency) { 702 Object target = JavaModel.getTarget(workspaceRoot, entryPath, 703 checkExistency); 704 if (target == null) 705 return; 706 707 if (target instanceof IResource) { 708 // internal target 709 IResource resource = (IResource) target; 710 IPackageFragmentRoot root = getPackageFragmentRoot(resource); 711 if (root != null) { 712 accumulatedRoots.add(root); 713 rootIDs.add(rootID); 714 } 715 } else { 716 // external target - only JARs allowed 717 // if (((java.io.File)target).isFile() && 718 // (ProjectPrefUtil.isArchiveFileName(entryPath.lastSegment()))) 719 // { 720 // accumulatedRoots.add( 721 // new JarPackageFragmentRoot(entryPath, this)); 722 // rootIDs.add(rootID); 723 // } 724 } 725 } else { 726 IPackageFragmentRoot root = getPackageFragmentRoot(entryPath); 727 if (root != null) { 728 accumulatedRoots.add(root); 729 rootIDs.add(rootID); 730 } 731 } 732 break; 733 734 // recurse into required project 735 case IClasspathEntry.CPE_PROJECT: 736 737 if (!retrieveExportedRoots) 738 return; 739 if (!insideOriginalProject && !resolvedEntry.isExported()) 740 return; 741 742 IResource member = workspaceRoot.findMember(entryPath); 743 if (member != null && member.getType() == IResource.PROJECT) {// double 744 // check 745 // if 746 // bound 747 // to 748 // project 749 // (23977) 750 IProject requiredProjectRsc = (IProject) member; 751 if (JavaProject.hasJavaNature(requiredProjectRsc)) { // special 752 // builder 753 // binary 754 // output 755 rootIDs.add(rootID); 756 JavaProject requiredProject = (JavaProject) JavaCore 757 .create(requiredProjectRsc); 758 requiredProject.computePackageFragmentRoots(requiredProject 759 .getResolvedClasspath(true), accumulatedRoots, 760 rootIDs, false, checkExistency, 761 retrieveExportedRoots); 762 } 763 break; 764 } 765 } 766 } 767 768 /** 769 * Returns (local/all) the package fragment roots identified by the given 770 * project's classpath. Note: this follows project classpath references to 771 * find required project contributions, eliminating duplicates silently. 772 * Only works with resolved entries 773 */ 774 public void computePackageFragmentRoots( 775 IClasspathEntry[] resolvedClasspath, ObjectVector accumulatedRoots, 776 HashSet rootIDs, boolean insideOriginalProject, 777 boolean checkExistency, boolean retrieveExportedRoots) 778 throws JavaModelException { 779 780 if (insideOriginalProject) { 781 rootIDs.add(rootID()); 782 } 783 for (int i = 0, length = resolvedClasspath.length; i < length; i++) { 784 computePackageFragmentRoots(resolvedClasspath[i], accumulatedRoots, 785 rootIDs, insideOriginalProject, checkExistency, 786 retrieveExportedRoots); 787 } 788 } 789 790 /** 791 * Compute the file name to use for a given shared property 792 */ 793 public String computeSharedPropertyFileName(QualifiedName qName) { 794 795 return '.' + qName.getLocalName(); 796 } 797 798 /* 799 * Returns whether the given resource is accessible through the children or 800 * the non-Java resources of this project. Returns true if the resource is 801 * not in the project. Assumes that the resource is a folder or a file. 802 */ 803 public boolean contains(IResource resource) { 804 805 IClasspathEntry[] classpath; 806 IPath output; 807 try { 808 classpath = getResolvedClasspath(true); 809 output = getOutputLocation(); 810 } catch (JavaModelException e) { 811 return false; 812 } 813 814 IPath fullPath = resource.getFullPath(); 815 IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null; 816 IClasspathEntry innerMostEntry = null; 817 for (int j = 0, cpLength = classpath.length; j < cpLength; j++) { 818 IClasspathEntry entry = classpath[j]; 819 820 IPath entryPath = entry.getPath(); 821 if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf( 822 entryPath)) 823 && entryPath.isPrefixOf(fullPath)) { 824 innerMostEntry = entry; 825 } 826 IPath entryOutput = classpath[j].getOutputLocation(); 827 if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) { 828 innerMostOutput = entryOutput; 829 } 830 } 831 if (innerMostEntry != null) { 832 // special case prj==src and nested output location 833 if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output 834 // isn't 835 // project 836 && innerMostEntry.getPath().segmentCount() == 1) { // 1 837 // segment 838 // must 839 // be 840 // project 841 // name 842 return false; 843 } 844 if (resource instanceof IFolder) { 845 // folders are always included in src/lib entries 846 return true; 847 } 848 switch (innerMostEntry.getEntryKind()) { 849 case IClasspathEntry.CPE_SOURCE: 850 // .class files are not visible in source folders 851 return true; // !net.sourceforge.phpdt.internal.compiler.util.ProjectPrefUtil.isClassFileName(fullPath.lastSegment()); 852 case IClasspathEntry.CPE_LIBRARY: 853 // .java files are not visible in library folders 854 return !net.sourceforge.phpdt.internal.compiler.util.Util 855 .isJavaFileName(fullPath.lastSegment()); 856 } 857 } 858 if (innerMostOutput != null) { 859 return false; 860 } 861 return true; 862 } 863 864 /** 865 * Record a new marker denoting a classpath problem 866 */ 867 IMarker createClasspathProblemMarker(IJavaModelStatus status) { 868 869 IMarker marker = null; 870 int severity; 871 String[] arguments = new String[0]; 872 boolean isCycleProblem = false, isClasspathFileFormatProblem = false; 873 switch (status.getCode()) { 874 875 case IJavaModelStatusConstants.CLASSPATH_CYCLE: 876 isCycleProblem = true; 877 if (JavaCore.ERROR.equals(getOption( 878 JavaCore.CORE_CIRCULAR_CLASSPATH, true))) { 879 severity = IMarker.SEVERITY_ERROR; 880 } else { 881 severity = IMarker.SEVERITY_WARNING; 882 } 883 break; 884 885 case IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT: 886 isClasspathFileFormatProblem = true; 887 severity = IMarker.SEVERITY_ERROR; 888 break; 889 890 default: 891 IPath path = status.getPath(); 892 if (path != null) 893 arguments = new String[] { path.toString() }; 894 if (JavaCore.ERROR.equals(getOption( 895 JavaCore.CORE_INCOMPLETE_CLASSPATH, true))) { 896 severity = IMarker.SEVERITY_ERROR; 897 } else { 898 severity = IMarker.SEVERITY_WARNING; 899 } 900 break; 901 } 902 903 try { 904 marker = getProject().createMarker( 905 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER); 906 marker.setAttributes(new String[] { IMarker.MESSAGE, 907 IMarker.SEVERITY, IMarker.LOCATION, 908 IJavaModelMarker.CYCLE_DETECTED, 909 IJavaModelMarker.CLASSPATH_FILE_FORMAT, 910 IJavaModelMarker.ID, IJavaModelMarker.ARGUMENTS, }, 911 new Object[] { status.getMessage(), 912 new Integer(severity), 913 Util.bind("classpath.buildPath"),//$NON-NLS-1$ 914 isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ 915 isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ 916 new Integer(status.getCode()), 917 Util.getProblemArgumentsForMarker(arguments), }); 918 } catch (CoreException e) { 919 } 920 return marker; 921 } 922 923 /** 924 * Returns a new element info for this element. 925 */ 926 protected Object createElementInfo() { 927 return new JavaProjectElementInfo(); 928 } 929 930 /* 931 * Returns a new search name environment for this project. This name 932 * environment first looks in the given working copies. 933 */ 934 // public ISearchableNameEnvironment 935 // newSearchableNameEnvironment(ICompilationUnit[] workingCopies) throws 936 // JavaModelException { 937 // return new SearchableEnvironment(this, workingCopies); 938 // } 939 /* 940 * Returns a new search name environment for this project. This name 941 * environment first looks in the working copies of the given owner. 942 */ 943 public ISearchableNameEnvironment newSearchableNameEnvironment( 944 WorkingCopyOwner owner) throws JavaModelException { 945 return new SearchableEnvironment(this, owner); 946 } 947 948 /** 949 * Reads and decode an XML classpath string 950 */ 951 protected IClasspathEntry[] decodeClasspath(String xmlClasspath, 952 boolean createMarker, boolean logProblems) { 953 954 ArrayList paths = new ArrayList(); 955 IClasspathEntry defaultOutput = null; 956 try { 957 if (xmlClasspath == null) 958 return null; 959 StringReader reader = new StringReader(xmlClasspath); 960 Element cpElement; 961 962 try { 963 DocumentBuilder parser = DocumentBuilderFactory.newInstance() 964 .newDocumentBuilder(); 965 cpElement = parser.parse(new InputSource(reader)) 966 .getDocumentElement(); 967 } catch (SAXException e) { 968 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$ 969 } catch (ParserConfigurationException e) { 970 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$ 971 } finally { 972 reader.close(); 973 } 974 975 if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$ 976 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$ 977 } 978 NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$ 979 int length = list.getLength(); 980 981 for (int i = 0; i < length; ++i) { 982 Node node = list.item(i); 983 if (node.getNodeType() == Node.ELEMENT_NODE) { 984 IClasspathEntry entry = ClasspathEntry.elementDecode( 985 (Element) node, this); 986 if (entry != null) { 987 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { 988 defaultOutput = entry; // separate output 989 } else { 990 paths.add(entry); 991 } 992 } 993 } 994 } 995 } catch (IOException e) { 996 // bad format 997 if (createMarker && this.getProject().isAccessible()) { 998 this 999 .createClasspathProblemMarker(new JavaModelStatus( 1000 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, 1001 Util 1002 .bind( 1003 "classpath.xmlFormatError", this.getElementName(), e.getMessage()))); //$NON-NLS-1$ 1004 } 1005 if (logProblems) { 1006 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ 1007 + "/.classpath, will mark classpath as invalid"); //$NON-NLS-1$ 1008 } 1009 return INVALID_CLASSPATH; 1010 } catch (Assert.AssertionFailedException e) { 1011 // failed creating CP entries from file 1012 if (createMarker && this.getProject().isAccessible()) { 1013 this 1014 .createClasspathProblemMarker(new JavaModelStatus( 1015 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, 1016 Util 1017 .bind( 1018 "classpath.illegalEntryInClasspathFile", this.getElementName(), e.getMessage()))); //$NON-NLS-1$ 1019 } 1020 if (logProblems) { 1021 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ 1022 + "/.classpath, will mark classpath as invalid"); //$NON-NLS-1$ 1023 } 1024 return INVALID_CLASSPATH; 1025 } 1026 int pathSize = paths.size(); 1027 if (pathSize > 0 || defaultOutput != null) { 1028 IClasspathEntry[] entries = new IClasspathEntry[pathSize 1029 + (defaultOutput == null ? 0 : 1)]; 1030 paths.toArray(entries); 1031 if (defaultOutput != null) 1032 entries[pathSize] = defaultOutput; // ensure output is last 1033 // item 1034 return entries; 1035 } else { 1036 return null; 1037 } 1038 } 1039 1040 /** 1041 * /** Removes the Java nature from the project. 1042 */ 1043 public void deconfigure() throws CoreException { 1044 1045 // deregister Java builder 1046 removeFromBuildSpec(PHPeclipsePlugin.BUILDER_PARSER_ID); 1047 } 1048 1049 /** 1050 * Returns a default class path. This is the root of the project 1051 */ 1052 protected IClasspathEntry[] defaultClasspath() throws JavaModelException { 1053 1054 return new IClasspathEntry[] { JavaCore.newSourceEntry(getProject() 1055 .getFullPath()) }; 1056 } 1057 1058 /** 1059 * Returns a default output location. This is the project bin folder 1060 */ 1061 protected IPath defaultOutputLocation() throws JavaModelException { 1062 return null; // getProject().getFullPath().append("bin"); 1063 // //$NON-NLS-1$ 1064 } 1065 1066 /** 1067 * Returns the XML String encoding of the class path. 1068 */ 1069 protected String encodeClasspath(IClasspathEntry[] classpath, 1070 IPath outputLocation, boolean indent) throws JavaModelException { 1071 try { 1072 ByteArrayOutputStream s = new ByteArrayOutputStream(); 1073 OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$ 1074 XMLWriter xmlWriter = new XMLWriter(writer); 1075 1076 xmlWriter.startTag("classpath", indent); //$NON-NLS-1$ 1077 for (int i = 0; i < classpath.length; ++i) { 1078 ((ClasspathEntry) classpath[i]).elementEncode(xmlWriter, 1079 this.project.getFullPath(), indent, true); 1080 } 1081 1082 if (outputLocation != null) { 1083 outputLocation = outputLocation.removeFirstSegments(1); 1084 outputLocation = outputLocation.makeRelative(); 1085 HashMap parameters = new HashMap(); 1086 parameters 1087 .put( 1088 "kind", ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT));//$NON-NLS-1$ 1089 parameters.put("path", String.valueOf(outputLocation));//$NON-NLS-1$ 1090 xmlWriter.printTag( 1091 "classpathentry", parameters, indent, true, true);//$NON-NLS-1$ 1092 } 1093 1094 xmlWriter.endTag("classpath", indent);//$NON-NLS-1$ 1095 writer.flush(); 1096 writer.close(); 1097 return s.toString("UTF8");//$NON-NLS-1$ 1098 } catch (IOException e) { 1099 throw new JavaModelException(e, 1100 IJavaModelStatusConstants.IO_EXCEPTION); 1101 } 1102 } 1103 1104 /** 1105 * Returns the XML String encoding of the class path. 1106 */ 1107 // protected String encodeClasspath(IClasspathEntry[] classpath, IPath 1108 // outputLocation, boolean useLineSeparator) throws JavaModelException { 1109 // 1110 // Document document = new DocumentImpl(); 1111 // Element cpElement = document.createElement("classpath"); //$NON-NLS-1$ 1112 // document.appendChild(cpElement); 1113 // 1114 // for (int i = 0; i < classpath.length; ++i) { 1115 // cpElement.appendChild(((ClasspathEntry)classpath[i]).elementEncode(document, 1116 // getProject().getFullPath())); 1117 // } 1118 // 1119 // if (outputLocation != null) { 1120 // outputLocation = outputLocation.removeFirstSegments(1); 1121 // outputLocation = outputLocation.makeRelative(); 1122 // Element oElement = document.createElement("classpathentry"); 1123 // //$NON-NLS-1$ 1124 // oElement.setAttribute("kind", 1125 // ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT)); //$NON-NLS-1$ 1126 // oElement.setAttribute("path", outputLocation.toString()); //$NON-NLS-1$ 1127 // cpElement.appendChild(oElement); 1128 // } 1129 // 1130 // // produce a String output 1131 // try { 1132 // ByteArrayOutputStream s = new ByteArrayOutputStream(); 1133 // OutputFormat format = new OutputFormat(); 1134 // if (useLineSeparator) { 1135 // format.setIndenting(true); 1136 // format.setLineSeparator(System.getProperty("line.separator")); 1137 // //$NON-NLS-1$ 1138 // } else { 1139 // format.setPreserveSpace(true); 1140 // } 1141 // Serializer serializer = 1142 // SerializerFactory.getSerializerFactory(Method.XML).makeSerializer( 1143 // new OutputStreamWriter(s, "UTF8"), //$NON-NLS-1$ 1144 // format); 1145 // serializer.asDOMSerializer().serialize(document); 1146 // return s.toString("UTF8"); //$NON-NLS-1$ 1147 // } catch (IOException e) { 1148 // throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); 1149 // } 1150 // } 1151 /** 1152 * Returns true if this handle represents the same Java project as the given 1153 * handle. Two handles represent the same project if they are identical or 1154 * if they represent a project with the same underlying resource and 1155 * occurrence counts. 1156 * 1157 * @see JavaElement#equals 1158 */ 1159 public boolean equals(Object o) { 1160 1161 if (this == o) 1162 return true; 1163 1164 if (!(o instanceof JavaProject)) 1165 return false; 1166 1167 JavaProject other = (JavaProject) o; 1168 return getProject().equals(other.getProject()) 1169 && occurrenceCount == other.occurrenceCount; 1170 } 1171 1172 public boolean exists() { 1173 if (!hasJavaNature(project)) 1174 return false; 1175 return super.exists(); 1176 } 1177 1178 /** 1179 * @see IJavaProject 1180 */ 1181 public IJavaElement findElement(IPath path) throws JavaModelException { 1182 1183 if (path == null || path.isAbsolute()) { 1184 throw new JavaModelException(new JavaModelStatus( 1185 IJavaModelStatusConstants.INVALID_PATH, path)); 1186 } 1187 // try { 1188 1189 String extension = path.getFileExtension(); 1190 if (extension == null) { 1191 String packageName = path.toString().replace(IPath.SEPARATOR, '.'); 1192 1193 // IPackageFragment[] pkgFragments = 1194 // getNameLookup().findPackageFragments(packageName, false); 1195 // if (pkgFragments == null) { 1196 return null; 1197 1198 // } else { 1199 // // try to return one that is a child of this project 1200 // for (int i = 0, length = pkgFragments.length; i < length; i++) { 1201 // 1202 // IPackageFragment pkgFragment = pkgFragments[i]; 1203 // if (this.equals(pkgFragment.getParent().getParent())) { 1204 // return pkgFragment; 1205 // } 1206 // } 1207 // // default to the first one 1208 // return pkgFragments[0]; 1209 // } 1210 } else if (extension.equalsIgnoreCase("java") //$NON-NLS-1$ 1211 || extension.equalsIgnoreCase("class")) { //$NON-NLS-1$ 1212 IPath packagePath = path.removeLastSegments(1); 1213 String packageName = packagePath.toString().replace( 1214 IPath.SEPARATOR, '.'); 1215 String typeName = path.lastSegment(); 1216 typeName = typeName.substring(0, typeName.length() 1217 - extension.length() - 1); 1218 String qualifiedName = null; 1219 if (packageName.length() > 0) { 1220 qualifiedName = packageName + "." + typeName; //$NON-NLS-1$ 1221 } else { 1222 qualifiedName = typeName; 1223 } 1224 // IType type = 1225 // getNameLookup().findType( 1226 // qualifiedName, 1227 // false, 1228 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES); 1229 // if (type != null) { 1230 // return type.getParent(); 1231 // } else { 1232 return null; 1233 // } 1234 } else { 1235 // unsupported extension 1236 return null; 1237 } 1238 // } catch (JavaModelException e) { 1239 // if (e.getStatus().getCode() 1240 // == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) { 1241 // return null; 1242 // } else { 1243 // throw e; 1244 // } 1245 // } 1246 } 1247 1248 /** 1249 * @see IJavaProject 1250 */ 1251 // public IPackageFragment findPackageFragment(IPath path) 1252 // throws JavaModelException { 1253 // 1254 // return findPackageFragment0(JavaProject.canonicalizedPath(path)); 1255 // } 1256 // 1257 // /** 1258 // * non path canonicalizing version 1259 // */ 1260 // public IPackageFragment findPackageFragment0(IPath path) 1261 // throws JavaModelException { 1262 // 1263 // return getNameLookup().findPackageFragment(path); 1264 // } 1265 /** 1266 * @see IJavaProject 1267 */ 1268 public IPackageFragmentRoot findPackageFragmentRoot(IPath path) 1269 throws JavaModelException { 1270 1271 return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path)); 1272 } 1273 1274 /** 1275 * no path canonicalization 1276 */ 1277 public IPackageFragmentRoot findPackageFragmentRoot0(IPath path) 1278 throws JavaModelException { 1279 1280 IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots(); 1281 if (!path.isAbsolute()) { 1282 throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$ 1283 } 1284 for (int i = 0; i < allRoots.length; i++) { 1285 IPackageFragmentRoot classpathRoot = allRoots[i]; 1286 if (classpathRoot.getPath().equals(path)) { 1287 return classpathRoot; 1288 } 1289 } 1290 return null; 1291 } 1292 1293 /** 1294 * @see IJavaProject 1295 */ 1296 public IPackageFragmentRoot[] findPackageFragmentRoots(IClasspathEntry entry) { 1297 try { 1298 IClasspathEntry[] classpath = this.getRawClasspath(); 1299 for (int i = 0, length = classpath.length; i < length; i++) { 1300 if (classpath[i].equals(entry)) { // entry may need to be 1301 // resolved 1302 return computePackageFragmentRoots(getResolvedClasspath( 1303 new IClasspathEntry[] { entry }, null, true, false, 1304 null/* no reverse map */), false); // don't 1305 // retrieve 1306 // exported 1307 // roots 1308 } 1309 } 1310 } catch (JavaModelException e) { 1311 } 1312 return new IPackageFragmentRoot[] {}; 1313 } 1314 1315 /** 1316 * @see IJavaProject#findType(String) 1317 */ 1318 // public IType findType(String fullyQualifiedName) throws 1319 // JavaModelException { 1320 // IType type = 1321 // this.getNameLookup().findType( 1322 // fullyQualifiedName, 1323 // false, 1324 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES); 1325 // if (type == null) { 1326 // // try to find enclosing type 1327 // int lastDot = fullyQualifiedName.lastIndexOf('.'); 1328 // if (lastDot == -1) return null; 1329 // type = this.findType(fullyQualifiedName.substring(0, lastDot)); 1330 // if (type != null) { 1331 // type = type.getType(fullyQualifiedName.substring(lastDot+1)); 1332 // if (!type.exists()) { 1333 // return null; 1334 // } 1335 // } 1336 // } 1337 // return type; 1338 // } 1339 /** 1340 * @see IJavaProject#findType(String, String) 1341 */ 1342 // public IType findType(String packageName, String typeQualifiedName) 1343 // throws JavaModelException { 1344 // return 1345 // this.getNameLookup().findType( 1346 // typeQualifiedName, 1347 // packageName, 1348 // false, 1349 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES); 1350 // } 1351 // 1352 /** 1353 * Remove all markers denoting classpath problems 1354 */ 1355 protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, 1356 boolean flushClasspathFormatMarkers) { 1357 try { 1358 IProject project = getProject(); 1359 if (project.exists()) { 1360 IMarker[] markers = project.findMarkers( 1361 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, 1362 IResource.DEPTH_ZERO); 1363 for (int i = 0, length = markers.length; i < length; i++) { 1364 IMarker marker = markers[i]; 1365 if (flushCycleMarkers && flushClasspathFormatMarkers) { 1366 marker.delete(); 1367 } else { 1368 String cycleAttr = (String) marker 1369 .getAttribute(IJavaModelMarker.CYCLE_DETECTED); 1370 String classpathFileFormatAttr = (String) marker 1371 .getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT); 1372 if ((flushCycleMarkers == (cycleAttr != null && cycleAttr 1373 .equals("true"))) //$NON-NLS-1$ 1374 && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr 1375 .equals("true")))) { //$NON-NLS-1$ 1376 marker.delete(); 1377 } 1378 } 1379 } 1380 } 1381 } catch (CoreException e) { 1382 } 1383 } 1384 1385 // /** 1386 // * @see Openable 1387 // */ 1388 // protected boolean generateInfos( 1389 // OpenableElementInfo info, 1390 // IProgressMonitor pm, 1391 // Map newElements, 1392 // IResource underlyingResource) throws JavaModelException { 1393 // 1394 // boolean validInfo = false; 1395 // try { 1396 // if (getProject().isOpen()) { 1397 // // put the info now, because computing the roots requires it 1398 // JavaModelManager.getJavaModelManager().putInfo(this, info); 1399 // 1400 // // compute the pkg fragment roots 1401 // updatePackageFragmentRoots(); 1402 // 1403 // // remember the timestamps of external libraries the first time they are 1404 // looked up 1405 // IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignore 1406 // unresolved variable*/); 1407 // for (int i = 0, length = resolvedClasspath.length; i < length; i++) { 1408 // IClasspathEntry entry = resolvedClasspath[i]; 1409 // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { 1410 // IPath path = entry.getPath(); 1411 // Object target = 1412 // JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, 1413 // true); 1414 // if (target instanceof java.io.File) { 1415 // Map externalTimeStamps = 1416 // JavaModelManager.getJavaModelManager().deltaProcessor.externalTimeStamps; 1417 // if (externalTimeStamps.get(path) == null) { 1418 // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target); 1419 // externalTimeStamps.put(path, new Long(timestamp)); 1420 // } 1421 // } 1422 // } 1423 // } 1424 // 1425 // // only valid if reaches here 1426 // validInfo = true; 1427 // } 1428 // } finally { 1429 // if (!validInfo) 1430 // JavaModelManager.getJavaModelManager().removeInfo(this); 1431 // } 1432 // return validInfo; 1433 // } 1434 1435 /** 1436 * @see IJavaProject 1437 */ 1438 public IPackageFragmentRoot[] getAllPackageFragmentRoots() 1439 throws JavaModelException { 1440 1441 return computePackageFragmentRoots(getResolvedClasspath(true), true); 1442 } 1443 1444 /** 1445 * Returns the classpath entry that refers to the given path or 1446 * <code>null</code> if there is no reference to the path. 1447 */ 1448 public IClasspathEntry getClasspathEntryFor(IPath path) 1449 throws JavaModelException { 1450 1451 IClasspathEntry[] entries = getExpandedClasspath(true); 1452 for (int i = 0; i < entries.length; i++) { 1453 if (entries[i].getPath().equals(path)) { 1454 return entries[i]; 1455 } 1456 } 1457 return null; 1458 } 1459 1460 /* 1461 * Returns the cycle marker associated with this project or null if none. 1462 */ 1463 public IMarker getCycleMarker() { 1464 try { 1465 IProject project = getProject(); 1466 if (project.exists()) { 1467 IMarker[] markers = project.findMarkers( 1468 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, 1469 IResource.DEPTH_ZERO); 1470 for (int i = 0, length = markers.length; i < length; i++) { 1471 IMarker marker = markers[i]; 1472 String cycleAttr = (String) marker 1473 .getAttribute(IJavaModelMarker.CYCLE_DETECTED); 1474 if (cycleAttr != null && cycleAttr.equals("true")) { //$NON-NLS-1$ 1475 return marker; 1476 } 1477 } 1478 } 1479 } catch (CoreException e) { 1480 } 1481 return null; 1482 } 1483 1484 /** 1485 * @see IJavaElement 1486 */ 1487 public int getElementType() { 1488 return JAVA_PROJECT; 1489 } 1490 1491 /** 1492 * This is a helper method returning the expanded classpath for the project, 1493 * as a list of classpath entries, where all classpath variable entries have 1494 * been resolved and substituted with their final target entries. All 1495 * project exports have been appended to project entries. 1496 * 1497 * @param ignoreUnresolvedVariable 1498 * boolean 1499 * @return IClasspathEntry[] 1500 * @throws JavaModelException 1501 */ 1502 public IClasspathEntry[] getExpandedClasspath( 1503 boolean ignoreUnresolvedVariable) throws JavaModelException { 1504 1505 return getExpandedClasspath(ignoreUnresolvedVariable, 1506 false/* don't create markers */, null, null); 1507 } 1508 1509 /* 1510 * @see JavaElement 1511 */ 1512 public IJavaElement getHandleFromMemento(String token, 1513 MementoTokenizer memento, WorkingCopyOwner owner) { 1514 switch (token.charAt(0)) { 1515 case JEM_COUNT: 1516 return getHandleUpdatingCountFromMemento(memento, owner); 1517 case JEM_PACKAGEFRAGMENTROOT: 1518 String rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH; 1519 token = null; 1520 while (memento.hasMoreTokens()) { 1521 token = memento.nextToken(); 1522 char firstChar = token.charAt(0); 1523 if (firstChar != JEM_PACKAGEFRAGMENT && firstChar != JEM_COUNT) { 1524 rootPath += token; 1525 } else { 1526 break; 1527 } 1528 } 1529 JavaElement root = (JavaElement) getPackageFragmentRoot(new Path( 1530 rootPath)); 1531 if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) { 1532 return root.getHandleFromMemento(token, memento, owner); 1533 } else { 1534 return root.getHandleFromMemento(memento, owner); 1535 } 1536 } 1537 return null; 1538 } 1539 1540 /** 1541 * Returns the <code>char</code> that marks the start of this handles 1542 * contribution to a memento. 1543 */ 1544 protected char getHandleMementoDelimiter() { 1545 1546 return JEM_JAVAPROJECT; 1547 } 1548 1549 /** 1550 * Internal variant which can create marker on project for invalid entries, 1551 * it will also perform classpath expansion in presence of project 1552 * prerequisites exporting their entries. 1553 * 1554 * @param ignoreUnresolvedVariable 1555 * boolean 1556 * @param generateMarkerOnError 1557 * boolean 1558 * @param preferredClasspaths 1559 * Map 1560 * @param preferredOutputs 1561 * Map 1562 * @return IClasspathEntry[] 1563 * @throws JavaModelException 1564 */ 1565 public IClasspathEntry[] getExpandedClasspath( 1566 boolean ignoreUnresolvedVariable, boolean generateMarkerOnError, 1567 Map preferredClasspaths, Map preferredOutputs) 1568 throws JavaModelException { 1569 1570 ObjectVector accumulatedEntries = new ObjectVector(); 1571 computeExpandedClasspath(this, ignoreUnresolvedVariable, 1572 generateMarkerOnError, new HashSet(5), accumulatedEntries, 1573 preferredClasspaths, preferredOutputs); 1574 1575 IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries 1576 .size()]; 1577 accumulatedEntries.copyInto(expandedPath); 1578 1579 return expandedPath; 1580 } 1581 1582 // /** 1583 // * Internal variant which can create marker on project for invalid 1584 // entries, 1585 // * it will also perform classpath expansion in presence of project 1586 // prerequisites 1587 // * exporting their entries. 1588 // */ 1589 // public IClasspathEntry[] getExpandedClasspath( 1590 // boolean ignoreUnresolvedVariable, 1591 // boolean generateMarkerOnError) throws JavaModelException { 1592 // 1593 // ObjectVector accumulatedEntries = new ObjectVector(); 1594 // computeExpandedClasspath(this, ignoreUnresolvedVariable, 1595 // generateMarkerOnError, new HashSet(5), accumulatedEntries); 1596 // 1597 // IClasspathEntry[] expandedPath = new 1598 // IClasspathEntry[accumulatedEntries.size()]; 1599 // accumulatedEntries.copyInto(expandedPath); 1600 // 1601 // return expandedPath; 1602 // } 1603 1604 /** 1605 * Find the specific Java command amongst the build spec of a given 1606 * description 1607 */ 1608 private ICommand getJavaCommand(IProjectDescription description) 1609 throws CoreException { 1610 1611 ICommand[] commands = description.getBuildSpec(); 1612 for (int i = 0; i < commands.length; ++i) { 1613 if (commands[i].getBuilderName().equals( 1614 PHPeclipsePlugin.BUILDER_PARSER_ID)) { 1615 return commands[i]; 1616 } 1617 } 1618 return null; 1619 } 1620 1621 /** 1622 * Convenience method that returns the specific type of info for a Java 1623 * project. 1624 */ 1625 protected JavaProjectElementInfo getJavaProjectElementInfo() 1626 throws JavaModelException { 1627 1628 return (JavaProjectElementInfo) getElementInfo(); 1629 } 1630 1631 /** 1632 * @see IJavaProject 1633 */ 1634 public NameLookup getNameLookup() throws JavaModelException { 1635 1636 JavaProjectElementInfo info = getJavaProjectElementInfo(); 1637 // lock on the project info to avoid race condition 1638 synchronized (info) { 1639 NameLookup nameLookup; 1640 if ((nameLookup = info.getNameLookup()) == null) { 1641 info.setNameLookup(nameLookup = new NameLookup(this)); 1642 } 1643 return nameLookup; 1644 } 1645 } 1646 1647 /* 1648 * Returns a new name lookup. This name lookup first looks in the given 1649 * working copies. 1650 */ 1651 public NameLookup newNameLookup(ICompilationUnit[] workingCopies) 1652 throws JavaModelException { 1653 1654 JavaProjectElementInfo info = getJavaProjectElementInfo(); 1655 // lock on the project info to avoid race condition while computing the 1656 // pkg fragment roots and package fragment caches 1657 // synchronized(info){ 1658 // return new NameLookup(info.getAllPackageFragmentRoots(this), 1659 // info.getAllPackageFragments(this), workingCopies); 1660 // } 1661 return null; 1662 } 1663 1664 /* 1665 * Returns a new name lookup. This name lookup first looks in the working 1666 * copies of the given owner. 1667 */ 1668 public NameLookup newNameLookup(WorkingCopyOwner owner) 1669 throws JavaModelException { 1670 1671 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 1672 ICompilationUnit[] workingCopies = owner == null ? null : manager 1673 .getWorkingCopies(owner, true/* add primary WCs */); 1674 return newNameLookup(workingCopies); 1675 } 1676 1677 // 1678 // /** 1679 // * Returns an array of non-java resources contained in the receiver. 1680 // */ 1681 // public Object[] getNonJavaResources() throws JavaModelException { 1682 // 1683 // return ((JavaProjectElementInfo) 1684 // getElementInfo()).getNonJavaResources(this); 1685 // } 1686 1687 /** 1688 * @see net.sourceforge.phpdt.core.IJavaProject#getOption(String, boolean) 1689 */ 1690 public String getOption(String optionName, boolean inheritJavaCoreOptions) { 1691 1692 if (JavaModelManager.OptionNames.contains(optionName)) { 1693 1694 Preferences preferences = getPreferences(); 1695 if (preferences == null || preferences.isDefault(optionName)) { 1696 return inheritJavaCoreOptions ? JavaCore.getOption(optionName) 1697 : null; 1698 } 1699 return preferences.getString(optionName).trim(); 1700 } 1701 return null; 1702 } 1703 1704 /** 1705 * @see net.sourceforge.phpdt.core.IJavaProject#getOptions(boolean) 1706 */ 1707 public Map getOptions(boolean inheritJavaCoreOptions) { 1708 1709 // initialize to the defaults from JavaCore options pool 1710 Map options = inheritJavaCoreOptions ? JavaCore.getOptions() 1711 : new Hashtable(5); 1712 1713 Preferences preferences = getPreferences(); 1714 if (preferences == null) 1715 return options; // cannot do better (non-Java project) 1716 HashSet optionNames = JavaModelManager.OptionNames; 1717 1718 // get preferences set to their default 1719 if (inheritJavaCoreOptions) { 1720 String[] defaultPropertyNames = preferences.defaultPropertyNames(); 1721 for (int i = 0; i < defaultPropertyNames.length; i++) { 1722 String propertyName = defaultPropertyNames[i]; 1723 if (optionNames.contains(propertyName)) { 1724 options.put(propertyName, preferences.getDefaultString( 1725 propertyName).trim()); 1726 } 1727 } 1728 } 1729 // get custom preferences not set to their default 1730 String[] propertyNames = preferences.propertyNames(); 1731 for (int i = 0; i < propertyNames.length; i++) { 1732 String propertyName = propertyNames[i]; 1733 if (optionNames.contains(propertyName)) { 1734 options.put(propertyName, preferences.getString(propertyName) 1735 .trim()); 1736 } 1737 } 1738 return options; 1739 } 1740 1741 /** 1742 * @see IJavaProject 1743 */ 1744 // public IPath getOutputLocation() throws JavaModelException { 1745 // 1746 // JavaModelManager.PerProjectInfo perProjectInfo = 1747 // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project); 1748 // IPath outputLocation = perProjectInfo.outputLocation; 1749 // if (outputLocation != null) return outputLocation; 1750 // 1751 // // force to read classpath - will position output location as well 1752 // this.getRawClasspath(); 1753 // outputLocation = perProjectInfo.outputLocation; 1754 // if (outputLocation == null) { 1755 // return defaultOutputLocation(); 1756 // } 1757 // return outputLocation; 1758 // } 1759 /** 1760 * @see IJavaProject 1761 */ 1762 public IPath getOutputLocation() throws JavaModelException { 1763 // Do not create marker but log problems while getting output location 1764 return this.getOutputLocation(false, true); 1765 } 1766 1767 /** 1768 * @param createMarkers 1769 * boolean 1770 * @param logProblems 1771 * boolean 1772 * @return IPath 1773 * @throws JavaModelException 1774 */ 1775 public IPath getOutputLocation(boolean createMarkers, boolean logProblems) 1776 throws JavaModelException { 1777 1778 JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo(); 1779 IPath outputLocation = perProjectInfo.outputLocation; 1780 if (outputLocation != null) 1781 return outputLocation; 1782 1783 // force to read classpath - will position output location as well 1784 this.getRawClasspath(createMarkers, logProblems); 1785 outputLocation = perProjectInfo.outputLocation; 1786 if (outputLocation == null) { 1787 return defaultOutputLocation(); 1788 } 1789 return outputLocation; 1790 } 1791 1792 /** 1793 * @return A handle to the package fragment root identified by the given 1794 * path. This method is handle-only and the element may or may not 1795 * exist. Returns <code>null</code> if unable to generate a handle 1796 * from the path (for example, an absolute path that has less than 1 1797 * segment. The path may be relative or absolute. 1798 */ 1799 public IPackageFragmentRoot getPackageFragmentRoot(IPath path) { 1800 if (!path.isAbsolute()) { 1801 path = getPath().append(path); 1802 } 1803 int segmentCount = path.segmentCount(); 1804 switch (segmentCount) { 1805 case 0: 1806 return null; 1807 case 1: 1808 // default root 1809 return getPackageFragmentRoot(getProject()); 1810 default: 1811 // a path ending with .jar/.zip is still ambiguous and could still 1812 // resolve to a source/lib folder 1813 // thus will try to guess based on existing resource 1814 // if (ProjectPrefUtil.isArchiveFileName(path.lastSegment())) { 1815 // IResource resource = 1816 // getProject().getWorkspace().getRoot().findMember(path); 1817 // if (resource != null && resource.getType() == IResource.FOLDER){ 1818 // return getPackageFragmentRoot(resource); 1819 // } 1820 // return getPackageFragmentRoot0(path); 1821 // } else { 1822 return getPackageFragmentRoot(getProject().getWorkspace().getRoot() 1823 .getFolder(path)); 1824 // } 1825 } 1826 } 1827 1828 /** 1829 * The path is known to match a source/library folder entry. 1830 */ 1831 public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) { 1832 if (path.segmentCount() == 1) { // default project root 1833 return getPackageFragmentRoot(getProject()); 1834 } 1835 return getPackageFragmentRoot(getProject().getWorkspace().getRoot() 1836 .getFolder(path)); 1837 } 1838 1839 /** 1840 * @see IJavaProject 1841 */ 1842 public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) { 1843 1844 switch (resource.getType()) { 1845 case IResource.FILE: 1846 // if (ProjectPrefUtil.isArchiveFileName(resource.getName())) { 1847 // return new JarPackageFragmentRoot(resource, this); 1848 // } else { 1849 return null; 1850 // } 1851 case IResource.FOLDER: 1852 return new PackageFragmentRoot(resource, this, resource.getName()); 1853 case IResource.PROJECT: 1854 return new PackageFragmentRoot(resource, this, ""); //$NON-NLS-1$ 1855 default: 1856 return null; 1857 } 1858 } 1859 1860 /** 1861 * @see IJavaProject 1862 */ 1863 // public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) { 1864 // 1865 // return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new 1866 // Path(jarPath))); 1867 // } 1868 // 1869 // /** 1870 // * no path canonicalization 1871 // */ 1872 // public IPackageFragmentRoot getPackageFragmentRoot0(IPath jarPath) { 1873 // 1874 // return new JarPackageFragmentRoot(jarPath, this); 1875 // } 1876 /** 1877 * @see IJavaProject 1878 */ 1879 public IPackageFragmentRoot[] getPackageFragmentRoots() 1880 throws JavaModelException { 1881 1882 Object[] children; 1883 int length; 1884 IPackageFragmentRoot[] roots; 1885 1886 System.arraycopy(children = getChildren(), 0, 1887 roots = new IPackageFragmentRoot[length = children.length], 0, 1888 length); 1889 1890 return roots; 1891 } 1892 1893 /** 1894 * @see IJavaProject 1895 * @deprecated 1896 */ 1897 public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) { 1898 return findPackageFragmentRoots(entry); 1899 } 1900 1901 /** 1902 * Returns the package fragment root prefixed by the given path, or an empty 1903 * collection if there are no such elements in the model. 1904 */ 1905 protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path) 1906 1907 throws JavaModelException { 1908 IPackageFragmentRoot[] roots = getAllPackageFragmentRoots(); 1909 ArrayList matches = new ArrayList(); 1910 1911 for (int i = 0; i < roots.length; ++i) { 1912 if (path.isPrefixOf(roots[i].getPath())) { 1913 matches.add(roots[i]); 1914 } 1915 } 1916 IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()]; 1917 matches.toArray(copy); 1918 return copy; 1919 } 1920 1921 /** 1922 * @see IJavaProject 1923 */ 1924 public IPackageFragment[] getPackageFragments() throws JavaModelException { 1925 1926 IPackageFragmentRoot[] roots = getPackageFragmentRoots(); 1927 return getPackageFragmentsInRoots(roots); 1928 } 1929 1930 /** 1931 * Returns all the package fragments found in the specified package fragment 1932 * roots. 1933 */ 1934 public IPackageFragment[] getPackageFragmentsInRoots( 1935 IPackageFragmentRoot[] roots) { 1936 1937 ArrayList frags = new ArrayList(); 1938 for (int i = 0; i < roots.length; i++) { 1939 IPackageFragmentRoot root = roots[i]; 1940 try { 1941 IJavaElement[] rootFragments = root.getChildren(); 1942 for (int j = 0; j < rootFragments.length; j++) { 1943 frags.add(rootFragments[j]); 1944 } 1945 } catch (JavaModelException e) { 1946 // do nothing 1947 } 1948 } 1949 IPackageFragment[] fragments = new IPackageFragment[frags.size()]; 1950 frags.toArray(fragments); 1951 return fragments; 1952 } 1953 1954 /* 1955 * @see IJavaElement 1956 */ 1957 public IPath getPath() { 1958 return this.getProject().getFullPath(); 1959 } 1960 1961 public JavaModelManager.PerProjectInfo getPerProjectInfo() 1962 throws JavaModelException { 1963 return JavaModelManager.getJavaModelManager() 1964 .getPerProjectInfoCheckExistence(this.project); 1965 } 1966 1967 /** 1968 * @see IJavaProject 1969 */ 1970 public IProject getProject() { 1971 1972 return project; 1973 } 1974 1975 /** 1976 * Sets the underlying kernel project of this Java project, and fills in its 1977 * parent and name. Called by IProject.getNature(). 1978 * 1979 * @see IProjectNature#setProject(IProject) 1980 */ 1981 public void setProject(IProject project) { 1982 1983 this.project = project; 1984 this.parent = JavaModelManager.getJavaModelManager().getJavaModel(); 1985 this.name = project.getName(); 1986 } 1987 1988 protected IProject getProject(String name) { 1989 return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name); 1990 } 1991 1992 public List getReferencedProjects() { 1993 List referencedProjects = new ArrayList(); 1994 1995 Iterator iterator = getLoadPathEntries().iterator(); 1996 while (iterator.hasNext()) { 1997 LoadPathEntry pathEntry = (LoadPathEntry) iterator.next(); 1998 if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT) 1999 referencedProjects.add(pathEntry.getProject()); 2000 } 2001 2002 return referencedProjects; 2003 } 2004 2005 /** 2006 * Returns the project custom preference pool. Project preferences may 2007 * include custom encoding. 2008 */ 2009 public Preferences getPreferences() { 2010 IProject project = getProject(); 2011 if (!JavaProject.hasJavaNature(project)) 2012 return null; 2013 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager 2014 .getJavaModelManager().getPerProjectInfo(project, true); 2015 Preferences preferences = perProjectInfo.preferences; 2016 if (preferences != null) 2017 return preferences; 2018 preferences = loadPreferences(); 2019 if (preferences == null) 2020 preferences = new Preferences(); 2021 perProjectInfo.preferences = preferences; 2022 return preferences; 2023 } 2024 2025 /** 2026 * @see IJavaProject 2027 */ 2028 // public IClasspathEntry[] getRawClasspath() throws JavaModelException { 2029 // 2030 // JavaModelManager.PerProjectInfo perProjectInfo = 2031 // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project); 2032 // IClasspathEntry[] classpath = perProjectInfo.classpath; 2033 // if (classpath != null) return classpath; 2034 // classpath = this.readClasspathFile(false/*don't create markers*/, 2035 // true/*log problems*/); 2036 // 2037 // // extract out the output location 2038 // IPath outputLocation = null; 2039 // if (classpath != null && classpath.length > 0) { 2040 // IClasspathEntry entry = classpath[classpath.length - 1]; 2041 // if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { 2042 // outputLocation = entry.getPath(); 2043 // IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1]; 2044 // System.arraycopy(classpath, 0, copy, 0, copy.length); 2045 // classpath = copy; 2046 // } 2047 // } 2048 // if (classpath == null) { 2049 // return defaultClasspath(); 2050 // } 2051 // /* Disable validate: classpath can contain CP variables and container 2052 // that need to be resolved 2053 // if (classpath != INVALID_CLASSPATH 2054 // && !JavaConventions.validateClasspath(this, classpath, 2055 // outputLocation).isOK()) { 2056 // classpath = INVALID_CLASSPATH; 2057 // } 2058 // */ 2059 // perProjectInfo.classpath = classpath; 2060 // perProjectInfo.outputLocation = outputLocation; 2061 // return classpath; 2062 // } 2063 /** 2064 * @see IJavaProject 2065 */ 2066 public IClasspathEntry[] getRawClasspath() throws JavaModelException { 2067 // Do not create marker but log problems while getting raw classpath 2068 return getRawClasspath(false, true); 2069 } 2070 2071 /* 2072 * Internal variant allowing to parameterize problem creation/logging 2073 */ 2074 public IClasspathEntry[] getRawClasspath(boolean createMarkers, 2075 boolean logProblems) throws JavaModelException { 2076 2077 JavaModelManager.PerProjectInfo perProjectInfo = null; 2078 IClasspathEntry[] classpath; 2079 if (createMarkers) { 2080 this.flushClasspathProblemMarkers(false/* cycle */, true/* format */); 2081 classpath = this.readClasspathFile(createMarkers, logProblems); 2082 } else { 2083 perProjectInfo = getPerProjectInfo(); 2084 classpath = perProjectInfo.rawClasspath; 2085 if (classpath != null) 2086 return classpath; 2087 classpath = this.readClasspathFile(createMarkers, logProblems); 2088 } 2089 // extract out the output location 2090 IPath outputLocation = null; 2091 if (classpath != null && classpath.length > 0) { 2092 IClasspathEntry entry = classpath[classpath.length - 1]; 2093 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { 2094 outputLocation = entry.getPath(); 2095 IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1]; 2096 System.arraycopy(classpath, 0, copy, 0, copy.length); 2097 classpath = copy; 2098 } 2099 } 2100 if (classpath == null) { 2101 return defaultClasspath(); 2102 } 2103 /* 2104 * Disable validate: classpath can contain CP variables and container 2105 * that need to be resolved if (classpath != INVALID_CLASSPATH && 2106 * !JavaConventions.validateClasspath(this, classpath, 2107 * outputLocation).isOK()) { classpath = INVALID_CLASSPATH; } 2108 */ 2109 if (!createMarkers) { 2110 perProjectInfo.rawClasspath = classpath; 2111 perProjectInfo.outputLocation = outputLocation; 2112 } 2113 return classpath; 2114 } 2115 2116 /** 2117 * @see IJavaProject#getRequiredProjectNames 2118 */ 2119 public String[] getRequiredProjectNames() throws JavaModelException { 2120 2121 return this.projectPrerequisites(getResolvedClasspath(true)); 2122 } 2123 2124 /** 2125 * @see IJavaProject 2126 */ 2127 public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry) 2128 throws JavaModelException { 2129 2130 return this.getResolvedClasspath(ignoreUnresolvedEntry, false); // generateMarkerOnError 2131 } 2132 2133 /** 2134 * Internal variant which can create marker on project for invalid entries 2135 * and caches the resolved classpath on perProjectInfo 2136 */ 2137 public IClasspathEntry[] getResolvedClasspath( 2138 boolean ignoreUnresolvedEntry, boolean generateMarkerOnError) 2139 throws JavaModelException { 2140 return getResolvedClasspath(ignoreUnresolvedEntry, 2141 generateMarkerOnError, true // returnResolutionInProgress 2142 ); 2143 // JavaModelManager manager = JavaModelManager.getJavaModelManager(); 2144 // JavaModelManager.PerProjectInfo perProjectInfo = 2145 // manager.getPerProjectInfoCheckExistence(project); 2146 // 2147 // // reuse cache if not needing to refresh markers or checking bound 2148 // variables 2149 // if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo 2150 // != null){ 2151 // // resolved path is cached on its info 2152 // IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath; 2153 // if (infoPath != null) return infoPath; 2154 // } 2155 // Map reverseMap = perProjectInfo == null ? null : new HashMap(5); 2156 // IClasspathEntry[] resolvedPath = getResolvedClasspath( 2157 // getRawClasspath(), 2158 // generateMarkerOnError ? getOutputLocation() : null, 2159 // ignoreUnresolvedEntry, 2160 // generateMarkerOnError, 2161 // reverseMap); 2162 // 2163 // if (perProjectInfo != null){ 2164 // if (perProjectInfo.classpath == null // .classpath file could not be 2165 // read 2166 // && generateMarkerOnError 2167 // && JavaProject.hasJavaNature(project)) { 2168 // this.createClasspathProblemMarker(new JavaModelStatus( 2169 // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, 2170 // Util.bind("classpath.cannotReadClasspathFile", 2171 // this.getElementName()))); //$NON-NLS-1$ 2172 // } 2173 // 2174 // perProjectInfo.lastResolvedClasspath = resolvedPath; 2175 // perProjectInfo.resolvedPathToRawEntries = reverseMap; 2176 // } 2177 // return resolvedPath; 2178 } 2179 2180 /* 2181 * Internal variant which can create marker on project for invalid entries 2182 * and caches the resolved classpath on perProjectInfo. If requested, return 2183 * a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being 2184 * resolved. 2185 */ 2186 public IClasspathEntry[] getResolvedClasspath( 2187 boolean ignoreUnresolvedEntry, boolean generateMarkerOnError, 2188 boolean returnResolutionInProgress) throws JavaModelException { 2189 2190 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 2191 JavaModelManager.PerProjectInfo perProjectInfo = null; 2192 if (ignoreUnresolvedEntry && !generateMarkerOnError) { 2193 perProjectInfo = getPerProjectInfo(); 2194 if (perProjectInfo != null) { 2195 // resolved path is cached on its info 2196 IClasspathEntry[] infoPath = perProjectInfo.resolvedClasspath; 2197 if (infoPath != null) { 2198 return infoPath; 2199 } else if (returnResolutionInProgress 2200 && manager.isClasspathBeingResolved(this)) { 2201 if (JavaModelManager.CP_RESOLVE_VERBOSE) { 2202 Util 2203 .verbose("CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$ 2204 " project: " + getElementName() + '\n' + //$NON-NLS-1$ 2205 " invocation stack trace:"); //$NON-NLS-1$ 2206 new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ 2207 } 2208 return RESOLUTION_IN_PROGRESS; 2209 } 2210 } 2211 } 2212 Map reverseMap = perProjectInfo == null ? null : new HashMap(5); 2213 IClasspathEntry[] resolvedPath = null; 2214 boolean nullOldResolvedCP = perProjectInfo != null 2215 && perProjectInfo.resolvedClasspath == null; 2216 try { 2217 // protect against misbehaving clients (see 2218 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=61040) 2219 if (nullOldResolvedCP) 2220 manager.setClasspathBeingResolved(this, true); 2221 resolvedPath = getResolvedClasspath(getRawClasspath( 2222 generateMarkerOnError, !generateMarkerOnError), 2223 generateMarkerOnError ? getOutputLocation() : null, 2224 ignoreUnresolvedEntry, generateMarkerOnError, reverseMap); 2225 } finally { 2226 if (nullOldResolvedCP) 2227 perProjectInfo.resolvedClasspath = null; 2228 } 2229 2230 if (perProjectInfo != null) { 2231 if (perProjectInfo.rawClasspath == null // .classpath file could not 2232 // be read 2233 && generateMarkerOnError 2234 && JavaProject.hasJavaNature(this.project)) { 2235 // flush .classpath format markers (bug 39877), but only when 2236 // file cannot be read (bug 42366) 2237 this.flushClasspathProblemMarkers(false, true); 2238 this 2239 .createClasspathProblemMarker(new JavaModelStatus( 2240 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, 2241 Util 2242 .bind( 2243 "classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$ 2244 } 2245 2246 perProjectInfo.resolvedClasspath = resolvedPath; 2247 perProjectInfo.resolvedPathToRawEntries = reverseMap; 2248 manager.setClasspathBeingResolved(this, false); 2249 } 2250 return resolvedPath; 2251 } 2252 2253 /** 2254 * Internal variant which can process any arbitrary classpath 2255 */ 2256 public IClasspathEntry[] getResolvedClasspath( 2257 IClasspathEntry[] classpathEntries, IPath projectOutputLocation, // only 2258 // set 2259 // if 2260 // needing 2261 // full 2262 // classpath 2263 // validation 2264 // (and 2265 // markers) 2266 boolean ignoreUnresolvedEntry, // if unresolved entries are met, 2267 // should it trigger initializations 2268 boolean generateMarkerOnError, Map reverseMap) // can be null if 2269 // not interested in 2270 // reverse mapping 2271 throws JavaModelException { 2272 2273 IJavaModelStatus status; 2274 if (generateMarkerOnError) { 2275 flushClasspathProblemMarkers(false, false); 2276 } 2277 2278 int length = classpathEntries.length; 2279 ArrayList resolvedEntries = new ArrayList(); 2280 2281 for (int i = 0; i < length; i++) { 2282 2283 IClasspathEntry rawEntry = classpathEntries[i]; 2284 IPath resolvedPath; 2285 status = null; 2286 2287 /* validation if needed */ 2288 // if (generateMarkerOnError || !ignoreUnresolvedEntry) { 2289 // status = JavaConventions.validateClasspathEntry(this, rawEntry, 2290 // false); 2291 // if (generateMarkerOnError && !status.isOK()) 2292 // createClasspathProblemMarker(status); 2293 // } 2294 switch (rawEntry.getEntryKind()) { 2295 2296 case IClasspathEntry.CPE_VARIABLE: 2297 2298 IClasspathEntry resolvedEntry = JavaCore 2299 .getResolvedClasspathEntry(rawEntry); 2300 if (resolvedEntry == null) { 2301 if (!ignoreUnresolvedEntry) 2302 throw new JavaModelException(status); 2303 } else { 2304 if (reverseMap != null 2305 && reverseMap.get(resolvedPath = resolvedEntry 2306 .getPath()) == null) 2307 reverseMap.put(resolvedPath, rawEntry); 2308 resolvedEntries.add(resolvedEntry); 2309 } 2310 break; 2311 2312 // case IClasspathEntry.CPE_CONTAINER : 2313 // 2314 // IClasspathContainer container = 2315 // PHPCore.getClasspathContainer(rawEntry.getPath(), this); 2316 // if (container == null){ 2317 // if (!ignoreUnresolvedEntry) throw new JavaModelException(status); 2318 // break; 2319 // } 2320 // 2321 // IClasspathEntry[] containerEntries = 2322 // container.getClasspathEntries(); 2323 // if (containerEntries == null) break; 2324 // 2325 // // container was bound 2326 // for (int j = 0, containerLength = containerEntries.length; j < 2327 // containerLength; j++){ 2328 // IClasspathEntry cEntry = containerEntries[j]; 2329 // 2330 // if (generateMarkerOnError) { 2331 // IJavaModelStatus containerStatus = 2332 // JavaConventions.validateClasspathEntry(this, cEntry, false); 2333 // if (!containerStatus.isOK()) 2334 // createClasspathProblemMarker(containerStatus); 2335 // } 2336 // // if container is exported, then its nested entries must in turn 2337 // be exported (21749) 2338 // if (rawEntry.isExported()){ 2339 // cEntry = new ClasspathEntry(cEntry.getContentKind(), 2340 // cEntry.getEntryKind(), cEntry.getPath(), 2341 // cEntry.getExclusionPatterns(), cEntry.getSourceAttachmentPath(), 2342 // cEntry.getSourceAttachmentRootPath(), cEntry.getOutputLocation(), 2343 // true); // duplicate container entry for tagging it as exported 2344 // } 2345 // if (reverseMap != null && reverseMap.get(resolvedPath = 2346 // cEntry.getPath()) == null) reverseMap.put(resolvedPath, 2347 // rawEntry); 2348 // resolvedEntries.add(cEntry); 2349 // } 2350 // break; 2351 2352 default: 2353 2354 if (reverseMap != null 2355 && reverseMap.get(resolvedPath = rawEntry.getPath()) == null) 2356 reverseMap.put(resolvedPath, rawEntry); 2357 resolvedEntries.add(rawEntry); 2358 2359 } 2360 } 2361 2362 IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries 2363 .size()]; 2364 resolvedEntries.toArray(resolvedPath); 2365 2366 // if (generateMarkerOnError && projectOutputLocation != null) { 2367 // status = JavaConventions.validateClasspath(this, resolvedPath, 2368 // projectOutputLocation); 2369 // if (!status.isOK()) createClasspathProblemMarker(status); 2370 // } 2371 return resolvedPath; 2372 } 2373 2374 /* 2375 * @see IJavaElement 2376 */ 2377 public IResource getResource() { 2378 return this.getProject(); 2379 } 2380 2381 /** 2382 * @see IJavaProject 2383 */ 2384 public ISearchableNameEnvironment getSearchableNameEnvironment() 2385 throws JavaModelException { 2386 2387 // JavaProjectElementInfo info = getJavaProjectElementInfo(); 2388 // if (info.getSearchableEnvironment() == null) { 2389 // info.setSearchableEnvironment(new SearchableEnvironment(this)); 2390 // } 2391 // return info.getSearchableEnvironment(); 2392 return null; 2393 } 2394 2395 /** 2396 * Retrieve a shared property on a project. If the property is not defined, 2397 * answers null. Note that it is orthogonal to IResource persistent 2398 * properties, and client code has to decide which form of storage to use 2399 * appropriately. Shared properties produce real resource files which can be 2400 * shared through a VCM onto a server. Persistent properties are not 2401 * shareable. 2402 * 2403 * @see JavaProject#setSharedProperty(String, String) 2404 */ 2405 public String getSharedProperty(String key) throws CoreException { 2406 2407 String property = null; 2408 IFile rscFile = getProject().getFile(key); 2409 if (rscFile.exists()) { 2410 property = new String(Util.getResourceContentsAsByteArray(rscFile)); 2411 } 2412 return property; 2413 } 2414 2415 /** 2416 * @see JavaElement 2417 */ 2418 // public SourceMapper getSourceMapper() { 2419 // 2420 // return null; 2421 // } 2422 /** 2423 * @see IJavaElement 2424 */ 2425 public IResource getUnderlyingResource() throws JavaModelException { 2426 if (!exists()) 2427 throw newNotPresentException(); 2428 return getProject(); 2429 } 2430 2431 /** 2432 * @see IJavaProject 2433 */ 2434 public boolean hasBuildState() { 2435 2436 return JavaModelManager.getJavaModelManager().getLastBuiltState( 2437 this.getProject(), null) != null; 2438 } 2439 2440 /** 2441 * @see IJavaProject 2442 */ 2443 public boolean hasClasspathCycle(IClasspathEntry[] preferredClasspath) { 2444 HashSet cycleParticipants = new HashSet(); 2445 updateCycleParticipants(preferredClasspath, new ArrayList(2), 2446 cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), 2447 new HashSet(2)); 2448 return !cycleParticipants.isEmpty(); 2449 } 2450 2451 public boolean hasCycleMarker() { 2452 return this.getCycleMarker() != null; 2453 } 2454 2455 public int hashCode() { 2456 return project.hashCode(); 2457 } 2458 2459 /** 2460 * Returns true if the given project is accessible and it has a java nature, 2461 * otherwise false. 2462 */ 2463 public static boolean hasJavaNature(IProject project) { 2464 try { 2465 return project.hasNature(PHPeclipsePlugin.PHP_NATURE_ID); 2466 } catch (CoreException e) { 2467 // project does not exist or is not open 2468 } 2469 return false; 2470 } 2471 2472 /** 2473 * Answers true if the project potentially contains any source. A project 2474 * which has no source is immutable. 2475 */ 2476 public boolean hasSource() { 2477 2478 // look if any source folder on the classpath 2479 // no need for resolved path given source folder cannot be abstracted 2480 IClasspathEntry[] entries; 2481 try { 2482 entries = this.getRawClasspath(); 2483 } catch (JavaModelException e) { 2484 return true; // unsure 2485 } 2486 for (int i = 0, max = entries.length; i < max; i++) { 2487 if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) { 2488 return true; 2489 } 2490 } 2491 return false; 2492 } 2493 2494 /** 2495 * Compare current classpath with given one to see if any different. Note 2496 * that the argument classpath contains its binary output. 2497 */ 2498 public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath, 2499 IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput) 2500 throws JavaModelException { 2501 2502 if (otherClasspathWithOutput != null 2503 && otherClasspathWithOutput.length > 0) { 2504 2505 int length = otherClasspathWithOutput.length; 2506 if (length == newClasspath.length + 1) { 2507 // output is amongst file entries (last one) 2508 2509 // compare classpath entries 2510 for (int i = 0; i < length - 1; i++) { 2511 if (!otherClasspathWithOutput[i].equals(newClasspath[i])) 2512 return false; 2513 } 2514 // compare binary outputs 2515 IClasspathEntry output = otherClasspathWithOutput[length - 1]; 2516 if (output.getContentKind() == ClasspathEntry.K_OUTPUT 2517 && output.getPath().equals(newOutputLocation)) 2518 return true; 2519 } 2520 } 2521 return false; 2522 } 2523 2524 /* 2525 * @see IJavaProject 2526 */ 2527 public boolean isOnClasspath(IJavaElement element) { 2528 IPath path = element.getPath(); 2529 switch (element.getElementType()) { 2530 case IJavaElement.PACKAGE_FRAGMENT_ROOT: 2531 if (!((IPackageFragmentRoot) element).isArchive()) { 2532 // ensure that folders are only excluded if all of their 2533 // children are excluded 2534 path = path.append("*"); //$NON-NLS-1$ 2535 } 2536 break; 2537 case IJavaElement.PACKAGE_FRAGMENT: 2538 if (!((IPackageFragmentRoot) element.getParent()).isArchive()) { 2539 // ensure that folders are only excluded if all of their 2540 // children are excluded 2541 path = path.append("*"); //$NON-NLS-1$ 2542 } 2543 break; 2544 } 2545 return this.isOnClasspath(path); 2546 } 2547 2548 private boolean isOnClasspath(IPath path) { 2549 IClasspathEntry[] classpath; 2550 try { 2551 classpath = this 2552 .getResolvedClasspath(true/* ignore unresolved variable */); 2553 } catch (JavaModelException e) { 2554 return false; // not a Java project 2555 } 2556 for (int i = 0; i < classpath.length; i++) { 2557 IClasspathEntry entry = classpath[i]; 2558 if (entry.getPath().isPrefixOf(path) 2559 && !Util.isExcluded(path, null, ((ClasspathEntry) entry) 2560 .fullExclusionPatternChars(), true)) { 2561 return true; 2562 } 2563 } 2564 return false; 2565 } 2566 2567 /* 2568 * @see IJavaProject 2569 */ 2570 public boolean isOnClasspath(IResource resource) { 2571 IPath path = resource.getFullPath(); 2572 2573 // ensure that folders are only excluded if all of their children are 2574 // excluded 2575 if (resource.getType() == IResource.FOLDER) { 2576 path = path.append("*"); //$NON-NLS-1$ 2577 } 2578 2579 return this.isOnClasspath(path); 2580 } 2581 2582 private IPath getPluginWorkingLocation() { 2583 return this.project.getWorkingLocation(JavaCore.PLUGIN_ID); 2584 } 2585 2586 /* 2587 * load preferences from a shareable format (VCM-wise) 2588 */ 2589 public Preferences loadPreferences() { 2590 2591 Preferences preferences = new Preferences(); 2592 2593 // File prefFile = 2594 // getProject().getLocation().append(PREF_FILENAME).toFile(); 2595 IPath projectMetaLocation = getPluginWorkingLocation(); 2596 if (projectMetaLocation != null) { 2597 File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile(); 2598 if (prefFile.exists()) { // load preferences from file 2599 InputStream in = null; 2600 try { 2601 in = new BufferedInputStream(new FileInputStream(prefFile)); 2602 preferences.load(in); 2603 return preferences; 2604 } catch (IOException e) { // problems loading preference store 2605 // - quietly ignore 2606 } finally { 2607 if (in != null) { 2608 try { 2609 in.close(); 2610 } catch (IOException e) { // ignore problems with 2611 // close 2612 } 2613 } 2614 } 2615 } 2616 } 2617 return null; 2618 } 2619 2620 /** 2621 * @see IJavaProject#newEvaluationContext 2622 */ 2623 // public IEvaluationContext newEvaluationContext() { 2624 // 2625 // return new EvaluationContextWrapper(new EvaluationContext(), this); 2626 // } 2627 /** 2628 * @see IJavaProject 2629 */ 2630 // public ITypeHierarchy newTypeHierarchy( 2631 // IRegion region, 2632 // IProgressMonitor monitor) 2633 // throws JavaModelException { 2634 // 2635 // if (region == null) { 2636 // throw new 2637 // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$ 2638 // } 2639 // CreateTypeHierarchyOperation op = 2640 // new CreateTypeHierarchyOperation(null, region, this, true); 2641 // runOperation(op, monitor); 2642 // return op.getResult(); 2643 // } 2644 /** 2645 * @see IJavaProject 2646 */ 2647 // public ITypeHierarchy newTypeHierarchy( 2648 // IType type, 2649 // IRegion region, 2650 // IProgressMonitor monitor) 2651 // throws JavaModelException { 2652 // 2653 // if (type == null) { 2654 // throw new 2655 // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullFocusType"));//$NON-NLS-1$ 2656 // } 2657 // if (region == null) { 2658 // throw new 2659 // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$ 2660 // } 2661 // CreateTypeHierarchyOperation op = 2662 // new CreateTypeHierarchyOperation(type, region, this, true); 2663 // runOperation(op, monitor); 2664 // return op.getResult(); 2665 // } 2666 // /** 2667 // * Open project if resource isn't closed 2668 // */ 2669 // protected void openWhenClosed(IProgressMonitor pm) throws 2670 // JavaModelException { 2671 // 2672 // if (!this.fProject.isOpen()) { 2673 // throw newNotPresentException(); 2674 // } else { 2675 // super.openWhenClosed(pm); 2676 // } 2677 // } 2678 public String[] projectPrerequisites(IClasspathEntry[] entries) 2679 throws JavaModelException { 2680 2681 ArrayList prerequisites = new ArrayList(); 2682 // need resolution 2683 entries = getResolvedClasspath(entries, null, true, false, null/* 2684 * no 2685 * reverse 2686 * map 2687 */); 2688 for (int i = 0, length = entries.length; i < length; i++) { 2689 IClasspathEntry entry = entries[i]; 2690 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { 2691 prerequisites.add(entry.getPath().lastSegment()); 2692 } 2693 } 2694 int size = prerequisites.size(); 2695 if (size == 0) { 2696 return NO_PREREQUISITES; 2697 } else { 2698 String[] result = new String[size]; 2699 prerequisites.toArray(result); 2700 return result; 2701 } 2702 } 2703 2704 /** 2705 * Reads the .classpath file from disk and returns the list of entries it 2706 * contains (including output location entry) Returns null if .classfile is 2707 * not present. Returns INVALID_CLASSPATH if it has a format problem. 2708 */ 2709 protected IClasspathEntry[] readClasspathFile(boolean createMarker, 2710 boolean logProblems) { 2711 2712 try { 2713 String xmlClasspath = getSharedProperty(CLASSPATH_FILENAME); 2714 if (xmlClasspath == null) 2715 return null; 2716 return decodeClasspath(xmlClasspath, createMarker, logProblems); 2717 } catch (CoreException e) { 2718 // file does not exist (or not accessible) 2719 if (createMarker && this.getProject().isAccessible()) { 2720 this 2721 .createClasspathProblemMarker(new JavaModelStatus( 2722 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, 2723 Util 2724 .bind( 2725 "classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$ 2726 } 2727 if (logProblems) { 2728 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ 2729 + "/.classpath, will revert to default classpath"); //$NON-NLS-1$ 2730 } 2731 } 2732 return null; 2733 } 2734 2735 /** 2736 * Removes the given builder from the build spec for the given project. 2737 */ 2738 protected void removeFromBuildSpec(String builderID) throws CoreException { 2739 2740 IProjectDescription description = getProject().getDescription(); 2741 ICommand[] commands = description.getBuildSpec(); 2742 for (int i = 0; i < commands.length; ++i) { 2743 if (commands[i].getBuilderName().equals(builderID)) { 2744 ICommand[] newCommands = new ICommand[commands.length - 1]; 2745 System.arraycopy(commands, 0, newCommands, 0, i); 2746 System.arraycopy(commands, i + 1, newCommands, i, 2747 commands.length - i - 1); 2748 description.setBuildSpec(newCommands); 2749 getProject().setDescription(description, null); 2750 return; 2751 } 2752 } 2753 } 2754 2755 /** 2756 * @see JavaElement#rootedAt(IJavaProject) 2757 */ 2758 public IJavaElement rootedAt(IJavaProject project) { 2759 return project; 2760 2761 } 2762 2763 /** 2764 * Answers an ID which is used to distinguish project/entries during package 2765 * fragment root computations 2766 */ 2767 public String rootID() { 2768 return "[PRJ]" + this.getProject().getFullPath(); //$NON-NLS-1$ 2769 } 2770 2771 /** 2772 * Saves the classpath in a shareable format (VCM-wise) only when necessary, 2773 * that is, if it is semantically different from the existing one in file. 2774 * Will never write an identical one. 2775 * 2776 * @return Return whether the .classpath file was modified. 2777 */ 2778 public boolean saveClasspath(IClasspathEntry[] newClasspath, 2779 IPath newOutputLocation) throws JavaModelException { 2780 2781 if (!getProject().exists()) 2782 return false; 2783 2784 IClasspathEntry[] fileEntries = readClasspathFile( 2785 false /* don't create markers */, false/* don't log problems */); 2786 if (fileEntries != null 2787 && isClasspathEqualsTo(newClasspath, newOutputLocation, 2788 fileEntries)) { 2789 // no need to save it, it is the same 2790 return false; 2791 } 2792 2793 // actual file saving 2794 try { 2795 setSharedProperty(CLASSPATH_FILENAME, encodeClasspath(newClasspath, 2796 newOutputLocation, true)); 2797 return true; 2798 } catch (CoreException e) { 2799 throw new JavaModelException(e); 2800 } 2801 } 2802 2803 /** 2804 * Save project custom preferences to shareable file (.jprefs) 2805 */ 2806 private void savePreferences(Preferences preferences) { 2807 2808 if (!JavaProject.hasJavaNature(this.project)) 2809 return; // ignore 2810 2811 if (preferences == null 2812 || (!preferences.needsSaving() && preferences.propertyNames().length != 0)) { 2813 // nothing to save 2814 return; 2815 } 2816 2817 // preferences need to be saved 2818 // the preferences file is located in the plug-in's state area 2819 // at a well-known name (.jprefs) 2820 // File prefFile = 2821 // this.project.getLocation().append(PREF_FILENAME).toFile(); 2822 File prefFile = getPluginWorkingLocation().append(PREF_FILENAME) 2823 .toFile(); 2824 if (preferences.propertyNames().length == 0) { 2825 // there are no preference settings 2826 // rather than write an empty file, just delete any existing file 2827 if (prefFile.exists()) { 2828 prefFile.delete(); // don't worry if delete unsuccessful 2829 } 2830 return; 2831 } 2832 2833 // write file, overwriting an existing one 2834 OutputStream out = null; 2835 try { 2836 // do it as carefully as we know how so that we don't lose/mangle 2837 // the setting in times of stress 2838 out = new BufferedOutputStream(new FileOutputStream(prefFile)); 2839 preferences.store(out, null); 2840 } catch (IOException e) { // problems saving preference store - 2841 // quietly ignore 2842 } finally { 2843 if (out != null) { 2844 try { 2845 out.close(); 2846 } catch (IOException e) { // ignore problems with close 2847 } 2848 } 2849 } 2850 } 2851 2852 /** 2853 * Update the Java command in the build spec (replace existing one if 2854 * present, add one first if none). 2855 */ 2856 private void setJavaCommand(IProjectDescription description, 2857 ICommand newCommand) throws CoreException { 2858 2859 ICommand[] oldCommands = description.getBuildSpec(); 2860 ICommand oldJavaCommand = getJavaCommand(description); 2861 ICommand[] newCommands; 2862 2863 if (oldJavaCommand == null) { 2864 // Add a Java build spec before other builders (1FWJK7I) 2865 newCommands = new ICommand[oldCommands.length + 1]; 2866 System 2867 .arraycopy(oldCommands, 0, newCommands, 1, 2868 oldCommands.length); 2869 newCommands[0] = newCommand; 2870 } else { 2871 for (int i = 0, max = oldCommands.length; i < max; i++) { 2872 if (oldCommands[i] == oldJavaCommand) { 2873 oldCommands[i] = newCommand; 2874 break; 2875 } 2876 } 2877 newCommands = oldCommands; 2878 } 2879 2880 // Commit the spec change into the project 2881 description.setBuildSpec(newCommands); 2882 getProject().setDescription(description, null); 2883 } 2884 2885 /** 2886 * @see net.sourceforge.phpdt.core.IJavaProject#setOptions(Map) 2887 */ 2888 public void setOptions(Map newOptions) { 2889 2890 Preferences preferences; 2891 setPreferences(preferences = new Preferences()); // always reset 2892 // (26255) 2893 if (newOptions != null) { 2894 Iterator keys = newOptions.keySet().iterator(); 2895 while (keys.hasNext()) { 2896 String key = (String) keys.next(); 2897 if (!JavaModelManager.OptionNames.contains(key)) 2898 continue; // unrecognized option 2899 // no filtering for encoding (custom encoding for project is 2900 // allowed) 2901 String value = (String) newOptions.get(key); 2902 preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty 2903 // string 2904 // isn't 2905 // the 2906 // default 2907 // (26251) 2908 preferences.setValue(key, value); 2909 } 2910 } 2911 2912 // persist options 2913 savePreferences(preferences); 2914 } 2915 2916 /** 2917 * @see IJavaProject 2918 */ 2919 public void setOutputLocation(IPath path, IProgressMonitor monitor) 2920 throws JavaModelException { 2921 2922 if (path == null) { 2923 throw new IllegalArgumentException(Util.bind("path.nullpath")); //$NON-NLS-1$ 2924 } 2925 if (path.equals(getOutputLocation())) { 2926 return; 2927 } 2928 this.setRawClasspath(SetClasspathOperation.ReuseClasspath, path, 2929 monitor); 2930 } 2931 2932 /* 2933 * Set cached preferences, no preference file is saved, only info is updated 2934 */ 2935 public void setPreferences(Preferences preferences) { 2936 IProject project = getProject(); 2937 if (!JavaProject.hasJavaNature(project)) 2938 return; // ignore 2939 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager 2940 .getJavaModelManager().getPerProjectInfo(project, true); 2941 perProjectInfo.preferences = preferences; 2942 } 2943 2944 /** 2945 * @see IJavaProject 2946 */ 2947 public void setRawClasspath(IClasspathEntry[] entries, 2948 IPath outputLocation, IProgressMonitor monitor) 2949 throws JavaModelException { 2950 2951 setRawClasspath(entries, outputLocation, monitor, true, // canChangeResource 2952 // (as per API 2953 // contract) 2954 getResolvedClasspath(true), // ignoreUnresolvedVariable 2955 true, // needValidation 2956 true); // need to save 2957 } 2958 2959 public void setRawClasspath(IClasspathEntry[] newEntries, 2960 IPath newOutputLocation, IProgressMonitor monitor, 2961 boolean canChangeResource, IClasspathEntry[] oldResolvedPath, 2962 boolean needValidation, boolean needSave) throws JavaModelException { 2963 2964 JavaModelManager manager = (JavaModelManager) JavaModelManager 2965 .getJavaModelManager(); 2966 try { 2967 IClasspathEntry[] newRawPath = newEntries; 2968 if (newRawPath == null) { // are we already with the default 2969 // classpath 2970 newRawPath = defaultClasspath(); 2971 } 2972 SetClasspathOperation op = new SetClasspathOperation(this, 2973 oldResolvedPath, newRawPath, newOutputLocation, 2974 canChangeResource, needValidation, needSave); 2975 runOperation(op, monitor); 2976 2977 } catch (JavaModelException e) { 2978 manager.flush(); 2979 throw e; 2980 } 2981 } 2982 2983 /** 2984 * @see IJavaProject 2985 */ 2986 public void setRawClasspath(IClasspathEntry[] entries, 2987 IProgressMonitor monitor) throws JavaModelException { 2988 2989 setRawClasspath(entries, SetClasspathOperation.ReuseOutputLocation, 2990 monitor, true, // canChangeResource (as per API contract) 2991 getResolvedClasspath(true), // ignoreUnresolvedVariable 2992 true, // needValidation 2993 true); // need to save 2994 } 2995 2996 /** 2997 * NOTE: <code>null</code> specifies default classpath, and an empty array 2998 * specifies an empty classpath. 2999 * 3000 * @exception NotPresentException 3001 * if this project does not exist. 3002 */ 3003 // protected void setRawClasspath0(IClasspathEntry[] rawEntries) 3004 // throws JavaModelException { 3005 // 3006 // JavaModelManager.PerProjectInfo info = 3007 // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project); 3008 // 3009 // synchronized (info) { 3010 // if (rawEntries != null) { 3011 // info.classpath = rawEntries; 3012 // } 3013 // 3014 // // clear cache of resolved classpath 3015 // info.lastResolvedClasspath = null; 3016 // info.resolvedPathToRawEntries = null; 3017 // } 3018 // } 3019 /** 3020 * Record a shared persistent property onto a project. Note that it is 3021 * orthogonal to IResource persistent properties, and client code has to 3022 * decide which form of storage to use appropriately. Shared properties 3023 * produce real resource files which can be shared through a VCM onto a 3024 * server. Persistent properties are not shareable. 3025 * 3026 * shared properties end up in resource files, and thus cannot be modified 3027 * during delta notifications (a CoreException would then be thrown). 3028 * 3029 * @see JavaProject#getSharedProperty(String key) 3030 */ 3031 public void setSharedProperty(String key, String value) 3032 throws CoreException { 3033 3034 IFile rscFile = getProject().getFile(key); 3035 InputStream inputStream = new ByteArrayInputStream(value.getBytes()); 3036 // update the resource content 3037 if (rscFile.exists()) { 3038 if (rscFile.isReadOnly()) { 3039 // provide opportunity to checkout read-only .classpath file 3040 // (23984) 3041 ResourcesPlugin.getWorkspace().validateEdit( 3042 new IFile[] { rscFile }, null); 3043 } 3044 rscFile.setContents(inputStream, IResource.FORCE, null); 3045 } else { 3046 rscFile.create(inputStream, IResource.FORCE, null); 3047 } 3048 } 3049 3050 /** 3051 * Update cycle markers for all java projects 3052 */ 3053 public static void updateAllCycleMarkers() throws JavaModelException { 3054 3055 // long start = System.currentTimeMillis(); 3056 3057 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 3058 IJavaProject[] projects = manager.getJavaModel().getJavaProjects(); 3059 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); 3060 3061 HashSet cycleParticipants = new HashSet(); 3062 HashSet traversed = new HashSet(); 3063 int length = projects.length; 3064 3065 // compute cycle participants 3066 ArrayList prereqChain = new ArrayList(); 3067 for (int i = 0; i < length; i++) { 3068 JavaProject project = (JavaProject) projects[i]; 3069 if (!traversed.contains(project.getPath())) { 3070 prereqChain.clear(); 3071 project.updateCycleParticipants(null, prereqChain, 3072 cycleParticipants, workspaceRoot, traversed); 3073 } 3074 } 3075 // System.out.println("updateAllCycleMarkers: " + 3076 // (System.currentTimeMillis() - start) + " ms"); 3077 3078 for (int i = 0; i < length; i++) { 3079 JavaProject project = (JavaProject) projects[i]; 3080 3081 if (cycleParticipants.contains(project.getPath())) { 3082 IMarker cycleMarker = project.getCycleMarker(); 3083 String circularCPOption = project.getOption( 3084 JavaCore.CORE_CIRCULAR_CLASSPATH, true); 3085 int circularCPSeverity = JavaCore.ERROR 3086 .equals(circularCPOption) ? IMarker.SEVERITY_ERROR 3087 : IMarker.SEVERITY_WARNING; 3088 if (cycleMarker != null) { 3089 // update existing cycle marker if needed 3090 try { 3091 int existingSeverity = ((Integer) cycleMarker 3092 .getAttribute(IMarker.SEVERITY)).intValue(); 3093 if (existingSeverity != circularCPSeverity) { 3094 cycleMarker.setAttribute(IMarker.SEVERITY, 3095 circularCPSeverity); 3096 } 3097 } catch (CoreException e) { 3098 throw new JavaModelException(e); 3099 } 3100 } else { 3101 // create new marker 3102 project 3103 .createClasspathProblemMarker(new JavaModelStatus( 3104 IJavaModelStatusConstants.CLASSPATH_CYCLE, 3105 project)); 3106 } 3107 } else { 3108 project.flushClasspathProblemMarkers(true, false); 3109 } 3110 } 3111 } 3112 3113 /** 3114 * If a cycle is detected, then cycleParticipants contains all the paths of 3115 * projects involved in this cycle (directly and indirectly), no cycle if 3116 * the set is empty (and started empty) 3117 */ 3118 public void updateCycleParticipants(IClasspathEntry[] preferredClasspath, 3119 ArrayList prereqChain, HashSet cycleParticipants, 3120 IWorkspaceRoot workspaceRoot, HashSet traversed) { 3121 3122 IPath path = this.getPath(); 3123 prereqChain.add(path); 3124 traversed.add(path); 3125 try { 3126 IClasspathEntry[] classpath = preferredClasspath == null ? getResolvedClasspath(true) 3127 : preferredClasspath; 3128 for (int i = 0, length = classpath.length; i < length; i++) { 3129 IClasspathEntry entry = classpath[i]; 3130 3131 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { 3132 IPath prereqProjectPath = entry.getPath(); 3133 int index = cycleParticipants.contains(prereqProjectPath) ? 0 3134 : prereqChain.indexOf(prereqProjectPath); 3135 if (index >= 0) { // refer to cycle, or in cycle itself 3136 for (int size = prereqChain.size(); index < size; index++) { 3137 cycleParticipants.add(prereqChain.get(index)); 3138 } 3139 } else { 3140 if (!traversed.contains(prereqProjectPath)) { 3141 IResource member = workspaceRoot 3142 .findMember(prereqProjectPath); 3143 if (member != null 3144 && member.getType() == IResource.PROJECT) { 3145 JavaProject project = (JavaProject) JavaCore 3146 .create((IProject) member); 3147 project.updateCycleParticipants(null, 3148 prereqChain, cycleParticipants, 3149 workspaceRoot, traversed); 3150 } 3151 } 3152 } 3153 } 3154 } 3155 } catch (JavaModelException e) { 3156 } 3157 prereqChain.remove(path); 3158 } 3159 3160 /** 3161 * Reset the collection of package fragment roots (local ones) - only if 3162 * opened. Need to check *all* package fragment roots in order to reset 3163 * NameLookup 3164 */ 3165 public void updatePackageFragmentRoots() { 3166 3167 if (this.isOpen()) { 3168 try { 3169 JavaProjectElementInfo info = getJavaProjectElementInfo(); 3170 3171 IClasspathEntry[] classpath = getResolvedClasspath(true); 3172 // NameLookup lookup = info.getNameLookup(); 3173 // if (lookup != null){ 3174 // IPackageFragmentRoot[] oldRoots = 3175 // lookup.fPackageFragmentRoots; 3176 // IPackageFragmentRoot[] newRoots = 3177 // computePackageFragmentRoots(classpath, true); 3178 // checkIdentical: { // compare all pkg fragment root lists 3179 // if (oldRoots.length == newRoots.length){ 3180 // for (int i = 0, length = oldRoots.length; i < length; i++){ 3181 // if (!oldRoots[i].equals(newRoots[i])){ 3182 // break checkIdentical; 3183 // } 3184 // } 3185 // return; // no need to update 3186 // } 3187 // } 3188 // info.setNameLookup(null); // discard name lookup (hold onto 3189 // roots) 3190 // } 3191 info.setNonJavaResources(null); 3192 info.setChildren(computePackageFragmentRoots(classpath, false)); 3193 3194 } catch (JavaModelException e) { 3195 try { 3196 close(); // could not do better 3197 } catch (JavaModelException ex) { 3198 } 3199 } 3200 } 3201 } 3202 3203 public void removeLoadPathEntry(IProject anotherPHPProject) { 3204 Iterator entries = getLoadPathEntries().iterator(); 3205 while (entries.hasNext()) { 3206 LoadPathEntry entry = (LoadPathEntry) entries.next(); 3207 if (entry.getType() == LoadPathEntry.TYPE_PROJECT 3208 && entry.getProject().getName().equals( 3209 anotherPHPProject.getName())) { 3210 getLoadPathEntries().remove(entry); 3211 fScratched = true; 3212 break; 3213 } 3214 } 3215 } 3216 3217 public void save() throws CoreException { 3218 if (fScratched) { 3219 InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML() 3220 .getBytes()); 3221 IFile loadPathsFile = getLoadPathEntriesFile(); 3222 if (!loadPathsFile.exists()) 3223 loadPathsFile.create(xmlPath, true, null); 3224 else 3225 loadPathsFile.setContents(xmlPath, true, false, null); 3226 3227 fScratched = false; 3228 } 3229 } 3230 3231 } 3232