/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Martin Oberhuber (Wind River) - [245937] setLinkLocation() detects non-change * Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support * Markus Schorn (Wind River) - [306575] Save snapshot location with project * Broadcom Corporation - build configurations and references *******************************************************************************/ package org.eclipse.core.internal.resources; import java.net.URI; import java.util.*; import java.util.Map.Entry; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.internal.events.BuildCommand; import org.eclipse.core.internal.utils.FileUtil; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; public class ProjectDescription extends ModelObject implements IProjectDescription { // constants private static final IBuildConfiguration[] EMPTY_BUILD_CONFIG_REFERENCE_ARRAY = new IBuildConfiguration[0]; private static final ICommand[] EMPTY_COMMAND_ARRAY = new ICommand[0]; private static final IProject[] EMPTY_PROJECT_ARRAY = new IProject[0]; private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final String EMPTY_STR = ""; //$NON-NLS-1$ protected static boolean isReading = false; //flags to indicate when we are in the middle of reading or writing a // workspace description //these can be static because only one description can be read at once. protected static boolean isWriting = false; protected ICommand[] buildSpec = EMPTY_COMMAND_ARRAY; protected String comment = EMPTY_STR; // Build configuration + References state /** Id of the currently active build configuration */ protected String activeConfiguration = IBuildConfiguration.DEFAULT_CONFIG_NAME; /** * The 'real' build configuration names set on this project. * This doesn't contain the generated 'default' build configuration with name * {@link IBuildConfiguration#DEFAULT_CONFIG_NAME} * when no build configurations have been defined. */ protected String[] configNames = EMPTY_STRING_ARRAY; // Static + Dynamic project level references protected IProject[] staticRefs = EMPTY_PROJECT_ARRAY; protected IProject[] dynamicRefs = EMPTY_PROJECT_ARRAY; /** Map from config name in this project -> build configurations in other projects */ protected HashMap<String, IBuildConfiguration[]> dynamicConfigRefs = new HashMap<String, IBuildConfiguration[]>(1); // Cache of the build configurations protected volatile IBuildConfiguration[] cachedBuildConfigs; // Cached build configuration references. Not persisted. protected Map<String, IBuildConfiguration[]> cachedConfigRefs = Collections.synchronizedMap(new HashMap<String, IBuildConfiguration[]>(1)); // Cached project level references. protected volatile IProject[] cachedRefs = null; /** * Map of (IPath -> LinkDescription) pairs for each linked resource * in this project, where IPath is the project relative path of the resource. */ protected HashMap<IPath,LinkDescription> linkDescriptions = null; /** * Map of (IPath -> LinkedList<FilterDescription>) pairs for each filtered resource * in this project, where IPath is the project relative path of the resource. */ protected HashMap<IPath,LinkedList<FilterDescription>> filterDescriptions = null; /** * Map of (String -> VariableDescription) pairs for each variable in this * project, where String is the name of the variable. */ protected HashMap<String,VariableDescription> variableDescriptions = null; // fields protected URI location = null; protected String[] natures = EMPTY_STRING_ARRAY; protected URI snapshotLocation= null; public ProjectDescription() { super(); } @SuppressWarnings("unchecked") public Object clone() { ProjectDescription clone = (ProjectDescription) super.clone(); //don't want the clone to have access to our internal link locations table or builders clone.linkDescriptions = null; clone.filterDescriptions = null; if (variableDescriptions != null) clone.variableDescriptions = (HashMap<String, VariableDescription>) variableDescriptions.clone(); clone.buildSpec = getBuildSpec(true); clone.dynamicConfigRefs = (HashMap<String, IBuildConfiguration[]>) dynamicConfigRefs.clone(); clone.cachedConfigRefs = Collections.synchronizedMap(new HashMap<String, IBuildConfiguration[]>(1)); clone.clearCachedReferences(null); return clone; } /** * Clear cached references for the specified build config name * or all if configName is null. */ private void clearCachedReferences(String configName) { if (configName == null) cachedConfigRefs.clear(); else cachedConfigRefs.remove(configName); cachedRefs = null; } /** * Returns a copy of the given array of build configs with all duplicates removed */ private IBuildConfiguration[] copyAndRemoveDuplicates(IBuildConfiguration[] values) { Set<IBuildConfiguration> set = new LinkedHashSet<IBuildConfiguration>(Arrays.asList(values)); return set.toArray(new IBuildConfiguration[set.size()]); } /** * Returns a copy of the given array with all duplicates removed */ private IProject[] copyAndRemoveDuplicates(IProject[] projects) { IProject[] result = new IProject[projects.length]; int count = 0; next: for (int i = 0; i < projects.length; i++) { IProject project = projects[i]; // scan to see if there are any other projects by the same name for (int j = 0; j < count; j++) if (project.equals(result[j])) continue next; // not found result[count++] = project; } if (count < projects.length) { //shrink array IProject[] reduced = new IProject[count]; System.arraycopy(result, 0, reduced, 0, count); return reduced; } return result; } /** * Helper to turn an array of projects into an array of {@link IBuildConfiguration} to the * projects' active configuration * Order is preserved - the buildConfigs appear for each project in the order * that the projects were specified. * @param projects projects to get the active configuration from * @return collection of build config references */ private Collection<BuildConfiguration> getBuildConfigReferencesFromProjects(IProject[] projects) { List<BuildConfiguration> refs = new ArrayList<BuildConfiguration>(projects.length); for (int i = 0; i < projects.length; i++) refs.add(new BuildConfiguration(projects[i], null)); return refs; } /** * Helper to fetch projects from an array of build configuration references * @param refs * @return List<IProject> */ private Collection<IProject> getProjectsFromBuildConfigRefs(IBuildConfiguration[] refs) { LinkedHashSet<IProject> projects = new LinkedHashSet<IProject>(refs.length); for (int i = 0; i < refs.length; i++) projects.add(refs[i].getProject()); return projects; } public String getActiveBuildConfig() { return activeConfiguration; } /** * Returns the union of the description's static and dynamic project references, * with duplicates omitted. The calculation is optimized by caching the result * Call the configuration based implementation. * @see #getAllBuildConfigReferences(String, boolean) */ public IProject[] getAllReferences(boolean makeCopy) { IProject[] projRefs = cachedRefs; if (projRefs == null) { IBuildConfiguration[] refs; if (hasBuildConfig(activeConfiguration)) refs = getAllBuildConfigReferences(activeConfiguration, false); else if (configNames.length > 0) refs = getAllBuildConfigReferences(configNames[0], false); else // No build configuration => fall-back to default refs = getAllBuildConfigReferences(IBuildConfiguration.DEFAULT_CONFIG_NAME, false); Collection<IProject> l = getProjectsFromBuildConfigRefs(refs); projRefs = cachedRefs = l.toArray(new IProject[l.size()]); } //still need to copy the result to prevent tampering with the cache return makeCopy ? (IProject[]) projRefs.clone() : projRefs; } /** * The main entrance point to fetch the full set of Project references. * * Returns the union of all the description's references. Includes static and dynamic * project level references as well as build configuration references for the configuration * with the given id. * Duplicates are omitted. The calculation is optimized by caching the result. * Note that these BuildConfiguration references may have <code>null</code> name. They must * be resolved using {@link BuildConfiguration#getBuildConfig()} before use. * Returns an empty array if the given configName does not exist in the description. */ public IBuildConfiguration[] getAllBuildConfigReferences(String configName, boolean makeCopy) { if (!hasBuildConfig(configName)) return EMPTY_BUILD_CONFIG_REFERENCE_ARRAY; IBuildConfiguration[] refs = cachedConfigRefs.get(configName); if (refs == null) { Set<IBuildConfiguration> references = new LinkedHashSet<IBuildConfiguration>(); IBuildConfiguration[] dynamicBuildConfigs = dynamicConfigRefs.containsKey(configName) ? dynamicConfigRefs.get(configName) : EMPTY_BUILD_CONFIG_REFERENCE_ARRAY; Collection<BuildConfiguration> dynamic = getBuildConfigReferencesFromProjects(dynamicRefs); Collection<BuildConfiguration> statik = getBuildConfigReferencesFromProjects(staticRefs); // Combine all references: // New build config references (which only come in dynamic form) trump all others. references.addAll(Arrays.asList(dynamicBuildConfigs)); // We preserve the previous order of static project references before dynamic project references references.addAll(statik); references.addAll(dynamic); refs = references.toArray(new IBuildConfiguration[references.size()]); cachedConfigRefs.put(configName, refs); } return makeCopy ? (IBuildConfiguration[]) refs.clone() : refs; } /** * Used by Project to get the buildConfigs on the description. * @return the project configurations */ public IBuildConfiguration[] getBuildConfigs(IProject project, boolean makeCopy) { IBuildConfiguration[] configs = cachedBuildConfigs; // Ensure project is up to date in the cache if (configs != null && !project.equals(configs[0].getProject())) configs = null; if (configs == null) { if (configNames.length == 0) configs = new IBuildConfiguration[] { new BuildConfiguration(project) }; else { configs = new IBuildConfiguration[configNames.length]; for (int i = 0; i < configs.length; i++) configs[i] = new BuildConfiguration(project, configNames[i]); } cachedBuildConfigs = configs; } return makeCopy ? (IBuildConfiguration[])configs.clone() : configs; } /* (non-Javadoc) * @see IProjectDescription#getBuildConfigReferences(String) */ public IBuildConfiguration[] getBuildConfigReferences(String configName) { return getBuildConfigRefs(configName, true); } public IBuildConfiguration[] getBuildConfigRefs(String configName, boolean makeCopy) { if (!hasBuildConfig(configName) || !dynamicConfigRefs.containsKey(configName)) return EMPTY_BUILD_CONFIG_REFERENCE_ARRAY; return makeCopy ? (IBuildConfiguration[])dynamicConfigRefs.get(configName).clone() : dynamicConfigRefs.get(configName); } /** * Returns the build configuration references map * @param makeCopy */ @SuppressWarnings("unchecked") public Map<String, IBuildConfiguration[]> getBuildConfigReferences(boolean makeCopy) { return makeCopy ? (Map<String, IBuildConfiguration[]>)dynamicConfigRefs.clone() : dynamicConfigRefs; } /* (non-Javadoc) * @see IProjectDescription#getBuildSpec() */ public ICommand[] getBuildSpec() { return getBuildSpec(true); } public ICommand[] getBuildSpec(boolean makeCopy) { //thread safety: copy reference in case of concurrent write ICommand[] oldCommands = this.buildSpec; if (oldCommands == null) return EMPTY_COMMAND_ARRAY; if (!makeCopy) return oldCommands; ICommand[] result = new ICommand[oldCommands.length]; for (int i = 0; i < result.length; i++) result[i] = (ICommand) ((BuildCommand) oldCommands[i]).clone(); return result; } /* (non-Javadoc) * @see IProjectDescription#getComment() */ public String getComment() { return comment; } /* (non-Javadoc) * @see IProjectDescription#getDynamicReferences() */ public IProject[] getDynamicReferences() { return getDynamicReferences(true); } public IProject[] getDynamicReferences(boolean makeCopy) { return makeCopy ? (IProject[])dynamicRefs.clone() : dynamicRefs; } /** * Returns the link location for the given resource name. Returns null if * no such link exists. */ public URI getLinkLocationURI(IPath aPath) { if (linkDescriptions == null) return null; LinkDescription desc = linkDescriptions.get(aPath); return desc == null ? null : desc.getLocationURI(); } /** * Returns the filter for the given resource name. Returns null if * no such filter exists. */ synchronized public LinkedList<FilterDescription> getFilter(IPath aPath) { if (filterDescriptions == null) return null; return filterDescriptions.get(aPath); } /** * Returns the map of link descriptions (IPath (project relative path) -> LinkDescription). * Since this method is only used internally, it never creates a copy. * Returns null if the project does not have any linked resources. */ public HashMap<IPath,LinkDescription> getLinks() { return linkDescriptions; } /** * Returns the map of filter descriptions (IPath (project relative path) -> LinkedList<FilterDescription>). * Since this method is only used internally, it never creates a copy. * Returns null if the project does not have any filtered resources. */ public HashMap<IPath, LinkedList<FilterDescription>> getFilters() { return filterDescriptions; } /** * Returns the map of variable descriptions (String (variable name) -> * VariableDescription). Since this method is only used internally, it never * creates a copy. Returns null if the project does not have any variables. */ public HashMap<String,VariableDescription> getVariables() { return variableDescriptions; } /** * @see IProjectDescription#getLocation() * @deprecated */ public IPath getLocation() { if (location == null) return null; return FileUtil.toPath(location); } /* (non-Javadoc) * @see IProjectDescription#getLocationURI() */ public URI getLocationURI() { return location; } /* (non-Javadoc) * @see IProjectDescription#getNatureIds() */ public String[] getNatureIds() { return getNatureIds(true); } public String[] getNatureIds(boolean makeCopy) { if (natures == null) return EMPTY_STRING_ARRAY; return makeCopy ? (String[]) natures.clone() : natures; } /* (non-Javadoc) * @see IProjectDescription#getReferencedProjects() */ public IProject[] getReferencedProjects() { return getReferencedProjects(true); } public IProject[] getReferencedProjects(boolean makeCopy) { if (staticRefs == null) return EMPTY_PROJECT_ARRAY; return makeCopy ? (IProject[]) staticRefs.clone() : staticRefs; } /** * Returns the URI to load a resource snapshot from. * May return <code>null</code> if no snapshot is set. * <p> * <strong>EXPERIMENTAL</strong>. This constant has been added as * part of a work in progress. There is no guarantee that this API will * work or that it will remain the same. Please do not use this API without * consulting with the Platform Core team. * </p> * @return the snapshot location URI, * or <code>null</code>. * @see IProject#loadSnapshot(int, URI, IProgressMonitor) * @see #setSnapshotLocationURI(URI) * @since 3.6 */ public URI getSnapshotLocationURI() { return snapshotLocation; } /* (non-Javadoc) * @see IProjectDescription#hasNature(String) */ public boolean hasNature(String natureID) { String[] natureIDs = getNatureIds(false); for (int i = 0; i < natureIDs.length; ++i) if (natureIDs[i].equals(natureID)) return true; return false; } /** * Helper method to compare two maps of Configuration Name -> IBuildConfigurationReference[] * @return boolean indicating if there are differences between the two maps */ private static boolean configRefsHaveChanges(Map<String, IBuildConfiguration[]> m1, Map<String, IBuildConfiguration[]> m2) { if (m1.size() != m2.size()) return true; for (Iterator<Entry<String,IBuildConfiguration[]>> it = m1.entrySet().iterator(); it.hasNext();) { Entry<String,IBuildConfiguration[]> e = it.next(); if (!m2.containsKey(e.getKey())) return true; if (!Arrays.equals(e.getValue(), m2.get(e.getKey()))) return true; } return false; } /** * Internal method to check if the description has a given build configuration. */ boolean hasBuildConfig(String buildConfigName) { Assert.isNotNull(buildConfigName); if (configNames.length == 0) return IBuildConfiguration.DEFAULT_CONFIG_NAME.equals(buildConfigName); for (int i = 0; i < configNames.length; i++) if (configNames[i].equals(buildConfigName)) return true; return false; } /** * Returns true if any private attributes of the description have changed. * Private attributes are those that are not stored in the project description * file (.project). */ public boolean hasPrivateChanges(ProjectDescription description) { if (location == null) { if (description.location != null) return true; } else if (!location.equals(description.location)) return true; if (!Arrays.equals(dynamicRefs, description.dynamicRefs)) return true; // Build Configuration state if (!activeConfiguration.equals(description.activeConfiguration)) return true; if (!Arrays.equals(configNames, description.configNames)) return true; // Configuration level references if (configRefsHaveChanges(dynamicConfigRefs, description.dynamicConfigRefs)) return true; return false; } /** * Returns true if any public attributes of the description have changed. * Public attributes are those that are stored in the project description * file (.project). */ public boolean hasPublicChanges(ProjectDescription description) { if (!getName().equals(description.getName())) return true; if (!comment.equals(description.getComment())) return true; //don't bother optimizing if the order has changed if (!Arrays.equals(buildSpec, description.getBuildSpec(false))) return true; if (!Arrays.equals(staticRefs, description.getReferencedProjects(false))) return true; if (!Arrays.equals(natures, description.getNatureIds(false))) return true; HashMap<IPath, LinkedList<FilterDescription>> otherFilters = description.getFilters(); if ((filterDescriptions == null) && (otherFilters != null)) return otherFilters != null; if ((filterDescriptions != null) && !filterDescriptions.equals(otherFilters)) return true; HashMap<String,VariableDescription> otherVariables = description.getVariables(); if ((variableDescriptions == null) && (otherVariables != null)) return true; if ((variableDescriptions != null) && !variableDescriptions.equals(otherVariables)) return true; final HashMap<IPath,LinkDescription> otherLinks = description.getLinks(); if (linkDescriptions != otherLinks) { if (linkDescriptions == null || !linkDescriptions.equals(otherLinks)) return true; } final URI otherSnapshotLoc= description.getSnapshotLocationURI(); if (snapshotLocation != otherSnapshotLoc) { if (snapshotLocation == null || !snapshotLocation.equals(otherSnapshotLoc)) return true; } return false; } /* (non-Javadoc) * @see IProjectDescription#newCommand() */ public ICommand newCommand() { return new BuildCommand(); } public void setActiveBuildConfig(String configName) { Assert.isNotNull(configName); if (!configName.equals(activeConfiguration)) clearCachedReferences(null); activeConfiguration = configName; } /* (non-Javadoc) * @see IProjectDescription#setBuildSpec(ICommand[]) */ public void setBuildSpec(ICommand[] value) { Assert.isLegal(value != null); //perform a deep copy in case clients perform further changes to the command ICommand[] result = new ICommand[value.length]; for (int i = 0; i < result.length; i++) { result[i] = (ICommand) ((BuildCommand) value[i]).clone(); //copy the reference to any builder instance from the old build spec //to preserve builder states if possible. for (int j = 0; j < buildSpec.length; j++) { if (result[i].equals(buildSpec[j])) { ((BuildCommand) result[i]).setBuilders(((BuildCommand) buildSpec[j]).getBuilders()); break; } } } buildSpec = result; } /* (non-Javadoc) * @see IProjectDescription#setComment(String) */ public void setComment(String value) { comment = value; } /* (non-Javadoc) * @see IProjectDescription#setDynamicReferences(IProject[]) */ public void setDynamicReferences(IProject[] value) { Assert.isLegal(value != null); dynamicRefs = copyAndRemoveDuplicates(value); clearCachedReferences(null); } public void setBuildConfigReferences(HashMap<String, IBuildConfiguration[]> refs) { dynamicConfigRefs = new HashMap<String, IBuildConfiguration[]>(refs); clearCachedReferences(null); } /* (non-Javadoc) * @see IProjectDescription#setDynamicConfigReferences(String, IBuildConfiguration[]) */ public void setBuildConfigReferences(String configName, IBuildConfiguration[] references) { Assert.isLegal(configName != null); Assert.isLegal(references != null); if (!hasBuildConfig(configName)) return; dynamicConfigRefs.put(configName, copyAndRemoveDuplicates(references)); clearCachedReferences(configName); } /* * (non-Javadoc) * @see IProjectDescription#setBuildConfigurations(String[]) */ public void setBuildConfigs(String[] names) { // Remove references for deleted buildConfigs LinkedHashSet<String> buildConfigNames = new LinkedHashSet<String>(); if (names == null || names.length == 0) { configNames = EMPTY_STRING_ARRAY; buildConfigNames.add(IBuildConfiguration.DEFAULT_CONFIG_NAME); } else { // Filter out duplicates for (String n : names) { Assert.isLegal(n != null); buildConfigNames.add(n); } if (buildConfigNames.size() == 1 && ((buildConfigNames.iterator().next())).equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) configNames = EMPTY_STRING_ARRAY; else configNames = buildConfigNames.toArray(new String[buildConfigNames.size()]); } // Remove references for deleted buildConfigs boolean modified = dynamicConfigRefs.keySet().retainAll(buildConfigNames); if (modified) clearCachedReferences(null); // Clear the cached IBuildConfiguration[] cachedBuildConfigs = null; } /** * Sets the map of link descriptions (String name -> LinkDescription). * Since this method is only used internally, it never creates a copy. May * pass null if this project does not have any linked resources */ public void setLinkDescriptions(HashMap<IPath,LinkDescription> linkDescriptions) { this.linkDescriptions = linkDescriptions; } /** * Sets the map of filter descriptions (String name -> LinkedList<LinkDescription>). * Since this method is only used internally, it never creates a copy. May * pass null if this project does not have any filtered resources */ public void setFilterDescriptions(HashMap<IPath,LinkedList<FilterDescription>> filterDescriptions) { this.filterDescriptions = filterDescriptions; } /** * Sets the map of variable descriptions (String name -> * VariableDescription). Since this method is only used internally, it never * creates a copy. May pass null if this project does not have any variables */ public void setVariableDescriptions(HashMap<String,VariableDescription> variableDescriptions) { this.variableDescriptions = variableDescriptions; } /** * Sets the description of a link. Setting to a description of null will * remove the link from the project description. * @return <code>true</code> if the description was actually changed, * <code>false</code> otherwise. * @since 3.5 returns boolean (was void before) */ @SuppressWarnings("unchecked") public boolean setLinkLocation(IPath path, LinkDescription description) { HashMap<IPath,LinkDescription> tempMap = linkDescriptions; if (description != null) { //addition or modification if (tempMap == null) tempMap = new HashMap<IPath,LinkDescription>(10); else //copy on write to protect against concurrent read tempMap = (HashMap<IPath, LinkDescription>) tempMap.clone(); Object oldValue = tempMap.put(path, description); if (oldValue!=null && description.equals(oldValue)) { //not actually changed anything return false; } linkDescriptions = tempMap; } else { //removal if (tempMap == null) return false; //copy on write to protect against concurrent access HashMap<IPath,LinkDescription> newMap = (HashMap<IPath,LinkDescription>) tempMap.clone(); Object oldValue = newMap.remove(path); if (oldValue == null) { //not actually changed anything return false; } linkDescriptions = newMap.size() == 0 ? null : newMap; } return true; } /** * Add the description of a filter. Setting to a description of null will * remove the filter from the project description. */ synchronized public void addFilter(IPath path, FilterDescription description) { Assert.isNotNull(description); if (filterDescriptions == null) filterDescriptions = new HashMap<IPath,LinkedList<FilterDescription>>(10); LinkedList<FilterDescription> descList = filterDescriptions.get(path); if (descList == null) { descList = new LinkedList<FilterDescription>(); filterDescriptions.put(path, descList); } descList.add(description); } /** * Add the description of a filter. Setting to a description of null will * remove the filter from the project description. */ synchronized public void removeFilter(IPath path, FilterDescription description) { if (filterDescriptions != null) { LinkedList<FilterDescription> descList = filterDescriptions.get(path); if (descList != null) { descList.remove(description); if (descList.size() == 0) { filterDescriptions.remove(path); if (filterDescriptions.size() == 0) filterDescriptions = null; } } } } /** * Sets the description of a variable. Setting to a description of null will * remove the variable from the project description. * @return <code>true</code> if the description was actually changed, * <code>false</code> otherwise. * @since 3.5 */ @SuppressWarnings("unchecked") public boolean setVariableDescription(String name, VariableDescription description) { HashMap<String,VariableDescription> tempMap = variableDescriptions; if (description != null) { // addition or modification if (tempMap == null) tempMap = new HashMap<String,VariableDescription>(10); else // copy on write to protect against concurrent read tempMap = (HashMap<String,VariableDescription>) tempMap.clone(); Object oldValue = tempMap.put(name, description); if (oldValue!=null && description.equals(oldValue)) { //not actually changed anything return false; } variableDescriptions = tempMap; } else { // removal if (tempMap == null) return false; // copy on write to protect against concurrent access HashMap<String,VariableDescription> newMap = (HashMap<String,VariableDescription>) tempMap.clone(); Object oldValue = newMap.remove(name); if (oldValue == null) { //not actually changed anything return false; } variableDescriptions = newMap.size() == 0 ? null : newMap; } return true; } /** * set the filters for a given resource. Setting to a description of null will * remove the filter from the project description. * @return <code>true</code> if the description was actually changed, * <code>false</code> otherwise. */ synchronized public boolean setFilters(IPath path, LinkedList<FilterDescription> descriptions) { if (descriptions != null) { // addition if (filterDescriptions == null) filterDescriptions = new HashMap<IPath,LinkedList<FilterDescription>>(10); Object oldValue = filterDescriptions.put(path, descriptions); if (oldValue!=null && descriptions.equals(oldValue)) { //not actually changed anything return false; } } else { // removal if (filterDescriptions == null) return false; Object oldValue = filterDescriptions.remove(path); if (oldValue == null) { //not actually changed anything return false; } if (filterDescriptions.size() == 0) filterDescriptions = null; } return true; } /* (non-Javadoc) * @see IProjectDescription#setLocation(IPath) */ public void setLocation(IPath path) { this.location = path == null ? null : URIUtil.toURI(path); } public void setLocationURI(URI location) { this.location = location; } /* (non-Javadoc) * @see IProjectDescription#setName(String) */ public void setName(String value) { super.setName(value); } /* (non-Javadoc) * @see IProjectDescription#setNatureIds(String[]) */ public void setNatureIds(String[] value) { natures = value.clone(); } /* (non-Javadoc) * @see IProjectDescription#setReferencedProjects(IProject[]) */ public void setReferencedProjects(IProject[] value) { Assert.isLegal(value != null); staticRefs = copyAndRemoveDuplicates(value); clearCachedReferences(null); } /** * Sets the location URI for a project snapshot that may be * loaded automatically when the project is created in a workspace. * <p> * <strong>EXPERIMENTAL</strong>. This method has been added as * part of a work in progress. There is no guarantee that this API will * work or that it will remain the same. Please do not use this API without * consulting with the Platform Core team. * </p> * @param snapshotLocation the location URI or * <code>null</code> to clear the setting * @see IProject#loadSnapshot(int, URI, IProgressMonitor) * @see #getSnapshotLocationURI() * @since 3.6 */ public void setSnapshotLocationURI(URI snapshotLocation) { this.snapshotLocation = snapshotLocation; } public URI getGroupLocationURI(IPath projectRelativePath) { return LinkDescription.VIRTUAL_LOCATION; } /** * Updates the dynamic build configuration and reference state to that of the passed in * description. * Copies in: * <ul> * <li>Active configuration name</li> * <li>Dynamic Project References</li> * <li>Build configurations list</li> * <li>Build Configuration References</li> * </ul> * @param description Project description to copy dynamic state from * @return boolean indicating if anything changed requing re-calculation of WS build order */ public boolean updateDynamicState(ProjectDescription description) { boolean changed = false; if (!activeConfiguration.equals(description.activeConfiguration)) { changed = true; activeConfiguration = description.activeConfiguration; } if (!Arrays.equals(dynamicRefs, description.dynamicRefs)) { changed = true; setDynamicReferences(description.dynamicRefs); } if (!Arrays.equals(configNames, description.configNames)) { changed = true; setBuildConfigs(description.configNames); } if (configRefsHaveChanges(dynamicConfigRefs, description.dynamicConfigRefs)) { changed = true; dynamicConfigRefs = new HashMap<String, IBuildConfiguration[]>(description.dynamicConfigRefs); } if (changed) clearCachedReferences(null); return changed; } }