1 11 package org.eclipse.core.internal.resources; 12 13 import java.util.*; 14 import org.eclipse.core.internal.events.ILifecycleListener; 15 import org.eclipse.core.internal.events.LifecycleEvent; 16 import org.eclipse.core.internal.utils.Messages; 17 import org.eclipse.core.internal.utils.Policy; 18 import org.eclipse.core.resources.*; 19 import org.eclipse.core.runtime.*; 20 import org.eclipse.osgi.util.NLS; 21 22 26 public class NatureManager implements ILifecycleListener, IManager { 27 protected Map descriptors; 29 30 protected Map natureEnablements; 32 33 protected Map buildersToNatures = null; 35 private static final byte WHITE = 0; 37 private static final byte GREY = 1; 38 private static final byte BLACK = 2; 39 40 protected NatureManager() { 41 super(); 42 } 43 44 49 protected String [] computeNatureEnablements(Project project) { 50 final ProjectDescription description = project.internalGetDescription(); 51 if (description == null) 52 return new String [0]; String [] natureIds = description.getNatureIds(); 54 int count = natureIds.length; 55 if (count == 0) 56 return natureIds; 57 58 HashSet candidates = new HashSet(count * 2); 60 HashMap setsToNatures = new HashMap(count); 62 for (int i = 0; i < count; i++) { 63 String id = natureIds[i]; 64 ProjectNatureDescriptor desc = (ProjectNatureDescriptor) getNatureDescriptor(id); 65 if (desc == null) 66 continue; 67 if (!desc.hasCycle) 68 candidates.add(id); 69 String [] setIds = desc.getNatureSetIds(); 71 for (int j = 0; j < setIds.length; j++) { 72 String set = setIds[j]; 73 ArrayList current = (ArrayList) setsToNatures.get(set); 74 if (current == null) { 75 current = new ArrayList(5); 76 setsToNatures.put(set, current); 77 } 78 current.add(id); 79 } 80 } 81 for (Iterator it = setsToNatures.values().iterator(); it.hasNext();) { 83 ArrayList setMembers = (ArrayList) it.next(); 84 if (setMembers.size() > 1) { 85 candidates.removeAll(setMembers); 86 } 87 } 88 String [] orderedCandidates = (String []) candidates.toArray(new String [candidates.size()]); 92 orderedCandidates = sortNatureSet(orderedCandidates); 93 for (int i = 0; i < orderedCandidates.length; i++) { 94 String id = orderedCandidates[i]; 95 IProjectNatureDescriptor desc = getNatureDescriptor(id); 96 String [] required = desc.getRequiredNatureIds(); 97 for (int j = 0; j < required.length; j++) { 98 if (!candidates.contains(required[j])) { 99 candidates.remove(id); 100 break; 101 } 102 } 103 } 104 return (String []) candidates.toArray(new String [candidates.size()]); 106 } 107 108 111 public IProjectNatureDescriptor getNatureDescriptor(String natureId) { 112 lazyInitialize(); 113 return (IProjectNatureDescriptor) descriptors.get(natureId); 114 } 115 116 119 public IProjectNatureDescriptor[] getNatureDescriptors() { 120 lazyInitialize(); 121 Collection values = descriptors.values(); 122 return (IProjectNatureDescriptor[]) values.toArray(new IProjectNatureDescriptor[values.size()]); 123 } 124 125 public void handleEvent(LifecycleEvent event) { 126 switch (event.kind) { 127 case LifecycleEvent.PRE_PROJECT_CHANGE : 128 case LifecycleEvent.PRE_PROJECT_CLOSE : 129 case LifecycleEvent.PRE_PROJECT_DELETE : 130 case LifecycleEvent.PRE_PROJECT_MOVE : 131 case LifecycleEvent.PRE_PROJECT_OPEN : 132 flushEnablements((IProject) event.resource); 133 } 134 } 135 136 139 protected void configureNature(final Project project, final String natureID, final MultiStatus errors) { 140 ISafeRunnable code = new ISafeRunnable() { 141 public void run() throws Exception { 142 IProjectNature nature = createNature(project, natureID); 143 nature.configure(); 144 ProjectInfo info = (ProjectInfo) project.getResourceInfo(false, true); 145 info.setNature(natureID, nature); 146 } 147 148 public void handleException(Throwable exception) { 149 if (exception instanceof CoreException) 150 errors.add(((CoreException) exception).getStatus()); 151 else 152 errors.add(new ResourceStatus(IResourceStatus.INTERNAL_ERROR, project.getFullPath(), NLS.bind(Messages.resources_errorNature, natureID), exception)); 153 } 154 }; 155 if (Policy.DEBUG_NATURES) { 156 System.out.println("Configuring nature: " + natureID + " on project: " + project.getName()); } 158 SafeRunner.run(code); 159 } 160 161 167 public void configureNatures(Project project, ProjectDescription oldDescription, ProjectDescription newDescription, MultiStatus status) { 168 HashSet oldNatures = new HashSet(Arrays.asList(oldDescription.getNatureIds(false))); 171 HashSet newNatures = new HashSet(Arrays.asList(newDescription.getNatureIds(false))); 172 if (oldNatures.equals(newNatures)) 173 return; 174 HashSet deletions = (HashSet) oldNatures.clone(); 175 HashSet additions = (HashSet) newNatures.clone(); 176 additions.removeAll(oldNatures); 177 deletions.removeAll(newNatures); 178 IStatus result = validateAdditions(newNatures, additions, project); 180 if (!result.isOK()) { 181 status.merge(result); 182 return; 183 } 184 result = validateRemovals(newNatures, deletions); 185 if (!result.isOK()) { 186 status.merge(result); 187 return; 188 } 189 oldDescription.setNatureIds(newDescription.getNatureIds(true)); 192 flushEnablements(project); 193 String [] ordered = null; 195 if (deletions.size() > 0) { 196 ordered = sortNatureSet((String []) deletions.toArray(new String [deletions.size()])); 197 for (int i = ordered.length; --i >= 0;) 198 deconfigureNature(project, ordered[i], status); 199 } 200 if (additions.size() > 0) { 201 ordered = sortNatureSet((String []) additions.toArray(new String [additions.size()])); 202 for (int i = 0; i < ordered.length; i++) 203 configureNature(project, ordered[i], status); 204 } 205 } 206 207 210 protected IProjectNature createNature(Project project, String natureID) throws CoreException { 211 IExtension extension = Platform.getExtensionRegistry().getExtension(ResourcesPlugin.PI_RESOURCES, ResourcesPlugin.PT_NATURES, natureID); 212 if (extension == null) { 213 String message = NLS.bind(Messages.resources_natureExtension, natureID); 214 throw new ResourceException(Platform.PLUGIN_ERROR, project.getFullPath(), message, null); 215 } 216 IConfigurationElement[] configs = extension.getConfigurationElements(); 217 if (configs.length < 1) { 218 String message = NLS.bind(Messages.resources_natureClass, natureID); 219 throw new ResourceException(Platform.PLUGIN_ERROR, project.getFullPath(), message, null); 220 } 221 IConfigurationElement config = null; 223 for (int i = 0; config == null && i < configs.length; i++) 224 if ("runtime".equalsIgnoreCase(configs[i].getName())) config = configs[i]; 226 if (config == null) { 227 String message = NLS.bind(Messages.resources_natureFormat, natureID); 228 throw new ResourceException(Platform.PLUGIN_ERROR, project.getFullPath(), message, null); 229 } 230 try { 231 IProjectNature nature = (IProjectNature) config.createExecutableExtension("run"); nature.setProject(project); 233 return nature; 234 } catch (ClassCastException e) { 235 String message = NLS.bind(Messages.resources_natureImplement, natureID); 236 throw new ResourceException(Platform.PLUGIN_ERROR, project.getFullPath(), message, e); 237 } 238 } 239 240 243 protected void deconfigureNature(final Project project, final String natureID, final MultiStatus status) { 244 final ProjectInfo info = (ProjectInfo) project.getResourceInfo(false, true); 245 IProjectNature existingNature = info.getNature(natureID); 246 if (existingNature == null) { 247 try { 249 existingNature = createNature(project, natureID); 250 } catch (CoreException e) { 251 Policy.log(e.getStatus()); 254 return; 255 } 256 } 257 final IProjectNature nature = existingNature; 258 ISafeRunnable code = new ISafeRunnable() { 259 public void run() throws Exception { 260 nature.deconfigure(); 261 info.setNature(natureID, null); 262 } 263 264 public void handleException(Throwable exception) { 265 if (exception instanceof CoreException) 266 status.add(((CoreException) exception).getStatus()); 267 else 268 status.add(new ResourceStatus(IResourceStatus.INTERNAL_ERROR, project.getFullPath(), NLS.bind(Messages.resources_natureDeconfig, natureID), exception)); 269 } 270 }; 271 if (Policy.DEBUG_NATURES) { 272 System.out.println("Deconfiguring nature: " + natureID + " on project: " + project.getName()); } 274 SafeRunner.run(code); 275 } 276 277 280 protected void detectCycles() { 281 Collection values = descriptors.values(); 282 ProjectNatureDescriptor[] natures = (ProjectNatureDescriptor[]) values.toArray(new ProjectNatureDescriptor[values.size()]); 283 for (int i = 0; i < natures.length; i++) 284 if (natures[i].colour == WHITE) 285 hasCycles(natures[i]); 286 } 287 288 291 protected IStatus failure(String reason) { 292 return new ResourceStatus(IResourceStatus.INVALID_NATURE_SET, reason); 293 } 294 295 299 public String findNatureForBuilder(String builderID) { 300 if (buildersToNatures == null) { 301 buildersToNatures = new HashMap(10); 302 IProjectNatureDescriptor[] descs = getNatureDescriptors(); 303 for (int i = 0; i < descs.length; i++) { 304 String natureId = descs[i].getNatureId(); 305 String [] builders = ((ProjectNatureDescriptor) descs[i]).getBuilderIds(); 306 for (int j = 0; j < builders.length; j++) { 307 buildersToNatures.put(builders[j], natureId); 309 } 310 } 311 } 312 return (String ) buildersToNatures.get(builderID); 313 } 314 315 protected void flushEnablements(IProject project) { 316 if (natureEnablements != null) { 317 natureEnablements.remove(project); 318 if (natureEnablements.size() == 0) { 319 natureEnablements = null; 320 } 321 } 322 } 323 324 328 protected String [] getEnabledNatures(Project project) { 329 String [] enabled; 330 if (natureEnablements != null) { 331 enabled = (String []) natureEnablements.get(project); 332 if (enabled != null) 333 return enabled; 334 } 335 enabled = computeNatureEnablements(project); 336 setEnabledNatures(project, enabled); 337 return enabled; 338 } 339 340 345 protected boolean hasCycles(ProjectNatureDescriptor desc) { 346 if (desc.colour == BLACK) { 347 return desc.hasCycle; 349 } 350 if (desc.colour == GREY) { 352 desc.hasCycle = true; 353 desc.colour = BLACK; 354 return true; 355 } 356 desc.colour = GREY; 358 359 String [] required = desc.getRequiredNatureIds(); 361 for (int i = 0; i < required.length; i++) { 362 ProjectNatureDescriptor dependency = (ProjectNatureDescriptor) getNatureDescriptor(required[i]); 363 if (dependency != null && hasCycles(dependency)) { 365 desc.hasCycle = true; 366 desc.colour = BLACK; 367 return true; 368 } 369 } 370 desc.hasCycle = false; 371 desc.colour = BLACK; 372 return false; 373 } 374 375 378 protected boolean hasLinks(IProject project) { 379 try { 380 IResource[] children = project.members(); 381 for (int i = 0; i < children.length; i++) 382 if (children[i].isLinked()) 383 return true; 384 } catch (CoreException e) { 385 Policy.log(e.getStatus()); 387 } 388 return false; 389 } 390 391 396 protected String hasSetOverlap(IProjectNatureDescriptor one, IProjectNatureDescriptor two) { 397 if (one == null || two == null) { 398 return null; 399 } 400 String [] setsOne = one.getNatureSetIds(); 402 String [] setsTwo = two.getNatureSetIds(); 403 for (int iOne = 0; iOne < setsOne.length; iOne++) { 404 for (int iTwo = 0; iTwo < setsTwo.length; iTwo++) { 405 if (setsOne[iOne].equals(setsTwo[iTwo])) { 406 return setsOne[iOne]; 407 } 408 } 409 } 410 return null; 411 } 412 413 416 protected void insert(ArrayList list, Set seen, String id) { 417 if (seen.contains(id)) 418 return; 419 seen.add(id); 420 IProjectNatureDescriptor desc = getNatureDescriptor(id); 422 if (desc != null) { 423 String [] prereqs = desc.getRequiredNatureIds(); 424 for (int i = 0; i < prereqs.length; i++) 425 insert(list, seen, prereqs[i]); 426 } 427 list.add(id); 428 } 429 430 435 public boolean isNatureEnabled(Project project, String id) { 436 String [] enabled = getEnabledNatures(project); 437 for (int i = 0; i < enabled.length; i++) { 438 if (enabled[i].equals(id)) 439 return true; 440 } 441 return false; 442 } 443 444 448 protected void lazyInitialize() { 449 if (descriptors != null) 450 return; 451 IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(ResourcesPlugin.PI_RESOURCES, ResourcesPlugin.PT_NATURES); 452 IExtension[] extensions = point.getExtensions(); 453 descriptors = new HashMap(extensions.length * 2 + 1); 454 for (int i = 0, imax = extensions.length; i < imax; i++) { 455 IProjectNatureDescriptor desc = null; 456 try { 457 desc = new ProjectNatureDescriptor(extensions[i]); 458 } catch (CoreException e) { 459 Policy.log(e.getStatus()); 460 } 461 if (desc != null) 462 descriptors.put(desc.getNatureId(), desc); 463 } 464 detectCycles(); 467 } 468 469 472 protected void setEnabledNatures(IProject project, String [] enablements) { 473 if (natureEnablements == null) 474 natureEnablements = new HashMap(20); 475 natureEnablements.put(project, enablements); 476 } 477 478 public void shutdown(IProgressMonitor monitor) { 479 } 481 482 485 public String [] sortNatureSet(String [] natureIds) { 486 int count = natureIds.length; 487 if (count == 0) 488 return natureIds; 489 ArrayList result = new ArrayList(count); 490 HashSet seen = new HashSet(count); for (int i = 0; i < count; i++) 492 insert(result, seen, natureIds[i]); 493 seen.clear(); 495 seen.addAll(Arrays.asList(natureIds)); 496 for (Iterator it = result.iterator(); it.hasNext();) { 497 Object id = it.next(); 498 if (!seen.contains(id)) 499 it.remove(); 500 } 501 return (String []) result.toArray(new String [result.size()]); 502 } 503 504 public void startup(IProgressMonitor monitor) { 505 ((Workspace) ResourcesPlugin.getWorkspace()).addLifecycleListener(this); 506 } 507 508 518 protected IStatus validateAdditions(HashSet newNatures, HashSet additions, IProject project) { 519 Boolean hasLinks = null; for (Iterator added = additions.iterator(); added.hasNext();) { 522 String id = (String ) added.next(); 523 IProjectNatureDescriptor desc = getNatureDescriptor(id); 525 if (desc == null) { 526 return failure(NLS.bind(Messages.natures_missingNature, id)); 527 } 528 if (((ProjectNatureDescriptor) desc).hasCycle) { 530 return failure(NLS.bind(Messages.natures_hasCycle, id)); 531 } 532 String [] required = desc.getRequiredNatureIds(); 534 for (int i = 0; i < required.length; i++) { 535 if (!newNatures.contains(required[i])) { 536 return failure(NLS.bind(Messages.natures_missingPrerequisite, id, required[i])); 537 } 538 } 539 for (Iterator all = newNatures.iterator(); all.hasNext();) { 541 String current = (String ) all.next(); 542 if (!current.equals(id)) { 543 String overlap = hasSetOverlap(desc, getNatureDescriptor(current)); 544 if (overlap != null) { 545 return failure(NLS.bind(Messages.natures_multipleSetMembers, overlap)); 546 } 547 } 548 } 549 if (!desc.isLinkingAllowed()) { 551 if (hasLinks == null) { 552 hasLinks = hasLinks(project) ? Boolean.TRUE : Boolean.FALSE; 553 } 554 if (hasLinks.booleanValue()) 555 return failure(NLS.bind(Messages.links_vetoNature, project.getName(), id)); 556 } 557 } 558 return Status.OK_STATUS; 559 } 560 561 569 public IStatus validateLinkCreation(String [] natureIds) { 570 for (int i = 0; i < natureIds.length; i++) { 571 IProjectNatureDescriptor desc = getNatureDescriptor(natureIds[i]); 572 if (desc != null && !desc.isLinkingAllowed()) { 573 String msg = NLS.bind(Messages.links_natureVeto, desc.getLabel()); 574 return new ResourceStatus(IResourceStatus.LINKING_NOT_ALLOWED, msg); 575 } 576 } 577 return Status.OK_STATUS; 578 } 579 580 590 protected IStatus validateRemovals(HashSet newNatures, HashSet deletions) { 591 for (Iterator it = newNatures.iterator(); it.hasNext();) { 593 String currentID = (String ) it.next(); 594 IProjectNatureDescriptor desc = getNatureDescriptor(currentID); 595 if (desc != null) { 596 String [] required = desc.getRequiredNatureIds(); 597 for (int i = 0; i < required.length; i++) { 598 if (deletions.contains(required[i])) { 599 return failure(NLS.bind(Messages.natures_invalidRemoval, required[i], currentID)); 600 } 601 } 602 } 603 } 604 return Status.OK_STATUS; 605 } 606 607 610 public IStatus validateNatureSet(String [] natureIds) { 611 int count = natureIds.length; 612 if (count == 0) 613 return Status.OK_STATUS; 614 String msg = Messages.natures_invalidSet; 615 MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INVALID_NATURE_SET, msg, null); 616 617 HashSet natures = new HashSet(count * 2); 619 HashSet sets = new HashSet(count); 621 for (int i = 0; i < count; i++) { 622 String id = natureIds[i]; 623 ProjectNatureDescriptor desc = (ProjectNatureDescriptor) getNatureDescriptor(id); 624 if (desc == null) { 625 result.add(failure(NLS.bind(Messages.natures_missingNature, id))); 626 continue; 627 } 628 if (desc.hasCycle) 629 result.add(failure(NLS.bind(Messages.natures_hasCycle, id))); 630 if (!natures.add(id)) 631 result.add(failure(NLS.bind(Messages.natures_duplicateNature, id))); 632 String [] setIds = desc.getNatureSetIds(); 634 for (int j = 0; j < setIds.length; j++) { 635 if (!sets.add(setIds[j])) 636 result.add(failure(NLS.bind(Messages.natures_multipleSetMembers, setIds[j]))); 637 } 638 } 639 for (int i = 0; i < count; i++) { 641 IProjectNatureDescriptor desc = getNatureDescriptor(natureIds[i]); 642 if (desc == null) 643 continue; 644 String [] required = desc.getRequiredNatureIds(); 645 for (int j = 0; j < required.length; j++) 646 if (!natures.contains(required[j])) 647 result.add(failure(NLS.bind(Messages.natures_missingPrerequisite, natureIds[i], required[j]))); 648 } 649 return result.isOK() ? Status.OK_STATUS : (IStatus) result; 651 } 652 } 653 | Popular Tags |