From 38fb615b8de0ddec965628db766621839902a617 Mon Sep 17 00:00:00 2001 From: Chris Recoskie Date: Wed, 21 Jan 2009 15:51:07 +0000 Subject: [PATCH] RESOLVED - bug 252966: ProjectDescription Storage: It should be possible to extend / override persistence mechanism https://bugs.eclipse.org/bugs/show_bug.cgi?id=252966 --- .../ScannerConfigProfileTests.java | 83 + .../ScannerDiscoveryTests.java | 1 + .../cdt/make/core/MakeScannerProvider.java | 24 +- .../IScannerConfigBuilderInfo2Set.java | 2 +- .../make/internal/core/ProjectTargets.java | 371 ++- .../scannerconfig2/PerProjectSICollector.java | 2 +- .../ScannerConfigInfoFactory2.java | 319 ++- .../META-INF/MANIFEST.MF | 3 +- .../tests/suite/AllManagedBuildTests.java | 28 +- .../CfgScannerConfigProfileManagerTests.java | 117 + ...CProjectDescriptionSerializationTests.java | 67 + .../core/ManagedBuildManager.java | 4 +- .../internal/core/ManagedBuildInfo.java | 4 +- .../core/ManagedConfigStorageElement.java | 36 +- .../internal/core/MapStorageElement.java | 86 +- .../ConfigurationDataProvider.java | 2 + .../IManagedScannerInfoCollector.java | 4 +- .../cdt/newmake/core/MakeScannerProvider.java | 25 +- .../cdescriptor/tests/CDescriptorTests.java | 342 ++- .../model/AllCProjectDescriptionTests.java | 2 +- .../model/BackwardCompatibilityTests.java | 3 +- .../model/CProjectDescriptionBasicTests.java | 4 + .../CProjectDescriptionStorageTests.java | 358 +++ .../index/tests/IndexProviderManagerTest.java | 10 +- .../model/CProjectDescriptionEvent.java | 14 + .../model/ICConfigExtensionReference.java | 10 +- .../settings/model/ICProjectDescription.java | 5 +- .../model/ICProjectDescriptionManager.java | 139 +- .../settings/model/ICSettingsStorage.java | 93 +- .../core/settings/model/ICStorageElement.java | 163 +- .../core/settings/model/XmlStorageUtil.java | 67 + .../extension/CConfigurationDataProvider.java | 2 +- .../model/util/ResourceChangeHandlerBase.java | 6 +- .../core/language/LanguageMappingStore.java | 111 +- .../cdt/internal/core/model/APathEntry.java | 11 + .../internal/core/model/CModelManager.java | 42 +- .../internal/core/model/CModelOperation.java | 19 +- .../cdt/internal/core/model/CProject.java | 8 +- .../core/model/DefaultPathEntryStore.java | 42 +- .../cdt/internal/core/model/MacroEntry.java | 5 + .../internal/core/model/MultiOperation.java | 7 +- .../cdt/internal/core/model/PathEntry.java | 5 + .../AbstractCProjectDescriptionStorage.java | 335 +++ .../CConfigurationDataProviderDescriptor.java | 2 +- .../model/CConfigurationDescription.java | 14 +- .../model/CConfigurationDescriptionCache.java | 15 +- .../model/CConfigurationSpecSettings.java | 137 +- .../settings/model/CProjectDescription.java | 184 +- .../model/CProjectDescriptionDelta.java | 4 +- .../model/CProjectDescriptionManager.java | 2061 +++++------------ .../CProjectDescriptionStorageManager.java | 402 ++++ .../core/settings/model/CStorage.java | 192 -- .../core/settings/model/CfgProxyCache.java | 14 +- .../ICProjectDescriptionStorageType.java | 161 ++ .../model/MultiConfigDescription.java | 17 + .../settings/model/ResourceChangeHandler.java | 93 +- .../SetCProjectDescriptionOperation.java | 169 +- .../core/settings/model/SettingsContext.java | 4 +- .../model/SynchronizedStorageElement.java | 192 ++ .../{ => xml}/InternalXmlStorageElement.java | 151 +- .../xml/XmlProjectDescriptionStorage.java | 804 +++++++ .../XmlProjectDescriptionStorageFactory.java | 31 + .../core/settings/model/xml/XmlStorage.java | 245 ++ .../model/xml}/XmlStorageElement.java | 237 +- .../xml2/XmlProjectDescriptionStorage2.java | 243 ++ .../XmlProjectDescriptionStorage2Factory.java | 33 + core/org.eclipse.cdt.core/plugin.properties | 3 +- core/org.eclipse.cdt.core/plugin.xml | 22 + .../schema/CProjectDescriptionStorage.exsd | 140 ++ .../src/org/eclipse/cdt/core/CCorePlugin.java | 7 +- .../org/eclipse/cdt/core/ICDescriptor.java | 108 +- .../eclipse/cdt/core/ICDescriptorManager.java | 61 +- .../cdt/core/ICDescriptorOperation.java | 11 + .../src/org/eclipse/cdt/core/ICExtension.java | 3 + .../cdt/core/ICExtensionReference.java | 38 +- .../internal/core/CConfigBasedDescriptor.java | 781 ++++--- .../core/CConfigBasedDescriptorManager.java | 876 +++---- .../core/CCorePluginResources.properties | 1 + .../UserDefinedVariableSupplier.java | 2 +- .../envvar/StorableEnvironmentLoader.java | 2 +- .../internal/ui/text/doctools/ProjectMap.java | 44 +- 81 files changed, 6753 insertions(+), 3732 deletions(-) create mode 100644 build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerConfigProfileTests.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/CfgScannerConfigProfileManagerTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionStorageTests.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/XmlStorageUtil.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/AbstractCProjectDescriptionStorage.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionStorageManager.java delete mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CStorage.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ICProjectDescriptionStorageType.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SynchronizedStorageElement.java rename core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/{ => xml}/InternalXmlStorageElement.java (60%) create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorage.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorageFactory.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorage.java rename core/org.eclipse.cdt.core/model/org/eclipse/cdt/{core/settings/model/util => internal/core/settings/model/xml}/XmlStorageElement.java (58%) create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2Factory.java create mode 100644 core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerConfigProfileTests.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerConfigProfileTests.java new file mode 100644 index 00000000000..2eff825735d --- /dev/null +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerConfigProfileTests.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.make.scannerdiscovery; + +import java.io.ByteArrayInputStream; + +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.cdt.make.core.MakeCorePlugin; +import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; +import org.eclipse.cdt.make.core.tests.StandardBuildTestHelper; +import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfileManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; + +/** + * This class tests ScannerConfigProfileManager + */ +public class ScannerConfigProfileTests extends BaseTestCase { + private IProject fCProject = null; + private IFile fCFile = null; + + protected void setUp() throws Exception { + fCProject = StandardBuildTestHelper.createProject("SCD", (IPath)null, MakeCorePlugin.MAKE_PROJECT_ID); + fCFile = fCProject.getProject().getFile("main.c"); + if (!fCFile.exists()) { + fCFile.create(new ByteArrayInputStream(" \n".getBytes()), false, new NullProgressMonitor()); + } + } + + protected void tearDown() throws Exception { + StandardBuildTestHelper.removeProject("SCDC"); + } + + /** + * Test Basic get of scanner config profile for a project + */ + public void testBasicScannerConfigProfile() throws CoreException { + // Add a scanner config profile to the project + IScannerConfigBuilderInfo2 scProjInfo = ScannerConfigProfileManager.createScannerConfigBuildInfo2(fCProject, ScannerConfigProfileManager.DEFAULT_SI_PROFILE_ID); + // Save + scProjInfo.save(); + + // Get all the settings and invert them + boolean autoDiscovery = scProjInfo.isAutoDiscoveryEnabled(); + scProjInfo.setAutoDiscoveryEnabled(!autoDiscovery); + boolean problemReport = scProjInfo.isProblemReportingEnabled(); + scProjInfo.setProblemReportingEnabled(!problemReport); + + boolean buildOutputParser = scProjInfo.isBuildOutputParserEnabled(); + scProjInfo.setBuildOutputParserEnabled(!buildOutputParser); + boolean buildOutputFileAction = scProjInfo.isBuildOutputFileActionEnabled(); + scProjInfo.setBuildOutputFileActionEnabled(!buildOutputFileAction); + String buildOutputFilePath = "dummyFile"; + scProjInfo.setBuildOutputFilePath(buildOutputFilePath); + + // Save + scProjInfo.save(); + + fCProject.close(new NullProgressMonitor()); + fCProject.open(new NullProgressMonitor()); + + scProjInfo = ScannerConfigProfileManager.createScannerConfigBuildInfo2(fCProject, ScannerConfigProfileManager.DEFAULT_SI_PROFILE_ID); + // Check that the previously set items have persisted... + Assert.isTrue(autoDiscovery != scProjInfo.isAutoDiscoveryEnabled()); + Assert.isTrue(problemReport != scProjInfo.isProblemReportingEnabled()); + Assert.isTrue(buildOutputParser != scProjInfo.isBuildOutputParserEnabled()); + Assert.isTrue(buildOutputFileAction != scProjInfo.isBuildOutputFileActionEnabled()); + Assert.isTrue(buildOutputFilePath.equals(scProjInfo.getBuildOutputFilePath())); + } + +} diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java index aec8eaa16df..080a975f030 100644 --- a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java @@ -24,5 +24,6 @@ public class ScannerDiscoveryTests extends TestSuite { addTestSuite(ScannerConfigDiscoveryTests.class); addTest(GCCScannerInfoConsoleParserTests.suite()); addTest(GCCPerFileBOPConsoleParserTests.suite()); + addTestSuite(ScannerConfigProfileTests.class); } } diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeScannerProvider.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeScannerProvider.java index 7c88ffe3a50..5755b4f73bc 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeScannerProvider.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeScannerProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.make.core; @@ -26,6 +27,7 @@ import org.eclipse.cdt.core.model.IMacroEntry; import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.resources.ScannerProvider; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRunnable; @@ -111,20 +113,20 @@ public class MakeScannerProvider extends ScannerProvider { * Loads the build file and parses the nodes for build information. The information is then associated with the resource for the * duration of the session. */ - private MakeScannerInfo loadScannerInfo(IProject project) throws CoreException { + private MakeScannerInfo loadScannerInfo(IProject project) throws CoreException { ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project); - Node child = descriptor.getProjectData(CDESCRIPTOR_ID).getFirstChild(); + ICStorageElement storage = descriptor.getProjectStorageElement(CDESCRIPTOR_ID); + ArrayList includes = new ArrayList(); ArrayList symbols = new ArrayList(); - while (child != null) { - if (child.getNodeName().equals(INCLUDE_PATH)) { + for (ICStorageElement child : storage.getChildren()) { + if (child.getName().equals(INCLUDE_PATH)) { // Add the path to the property list includes.add( ((Element)child).getAttribute(PATH)); - } else if (child.getNodeName().equals(DEFINED_SYMBOL)) { + } else if (child.getName().equals(DEFINED_SYMBOL)) { // Add the symbol to the symbol list symbols.add( ((Element)child).getAttribute(SYMBOL)); } - child = child.getNextSibling(); } MakeScannerInfo info = new MakeScannerInfo(project); info.setIncludePaths((String[])includes.toArray(new String[includes.size()])); @@ -193,15 +195,11 @@ public class MakeScannerProvider extends ScannerProvider { ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project); - Element rootElement = descriptor.getProjectData(CDESCRIPTOR_ID); + ICStorageElement rootElement = descriptor.getProjectStorageElement(CDESCRIPTOR_ID); // Clear out all current children // Note: Probably would be a better idea to merge in the data - Node child = rootElement.getFirstChild(); - while (child != null) { - rootElement.removeChild(child); - child = rootElement.getFirstChild(); - } + rootElement.clear(); descriptor.saveProjectData(); migrateToCPathEntries(scannerInfo); diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo2Set.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo2Set.java index 01047f709ca..db4f250eaf3 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo2Set.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo2Set.java @@ -21,7 +21,7 @@ public interface IScannerConfigBuilderInfo2Set { * * @return InfoContext - to IScannerConfigBuilderInfo2 map */ - Map getInfoMap(); + Map getInfoMap(); IScannerConfigBuilderInfo2 getInfo(InfoContext context); diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/ProjectTargets.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/ProjectTargets.java index b098e5b9bc4..c24abe6d090 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/ProjectTargets.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/ProjectTargets.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) - Use ICStorageElement *******************************************************************************/ package org.eclipse.cdt.make.internal.core; @@ -14,24 +15,17 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ICDescriptor; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.core.settings.model.XmlStorageUtil; import org.eclipse.cdt.make.core.IMakeCommonBuildInfo; import org.eclipse.cdt.make.core.IMakeTarget; import org.eclipse.cdt.make.core.MakeCorePlugin; @@ -42,10 +36,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; public class ProjectTargets { @@ -65,7 +55,7 @@ public class ProjectTargets { private static final String BAD_TARGET = "buidlTarget"; //$NON-NLS-1$ private static final String TARGET = "buildTarget"; //$NON-NLS-1$ - private HashMap targetMap = new HashMap(); + private HashMap> targetMap = new HashMap>(); private IProject project; @@ -75,68 +65,54 @@ public class ProjectTargets { this.project = project; - Document document = translateCDTProjectToDocument(); + ICStorageElement rootElement = null; + try { + ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(getProject(), true); + rootElement = descriptor.getProjectStorageElement(MAKE_TARGET_KEY); - //Historical ... fall back to the workspace and look in previous - // location - if (document == null || !document.hasChildNodes()) { - IPath targetFilePath = MakeCorePlugin.getDefault().getStateLocation().append(project.getName()).addFileExtension( - TARGETS_EXT); - targetFile = targetFilePath.toFile(); - try { - InputStream input = new FileInputStream(targetFile); - document = translateInputStreamToDocument(input); - writeTargets = true; // update cdtproject - } catch (FileNotFoundException ex) { - /* Ignore */ - } - } - - if (document != null) { - extractMakeTargetsFromDocument(document, manager); - if (writeTargets) { + //Historical ... fall back to the workspace and look in previous XML file location + if (rootElement.getChildren().length == 0) { + IPath targetFilePath = MakeCorePlugin.getDefault().getStateLocation().append(project.getName()).addFileExtension( + TARGETS_EXT); + targetFile = targetFilePath.toFile(); try { - Document doc = getAsXML(); - translateDocumentToCDTProject(doc); - } catch (Exception e) { - targetFile = null; - } - if (targetFile != null) { - targetFile.delete(); // removed old + InputStream input = new FileInputStream(targetFile); + ICStorageElement oldElement = translateInputStreamToDocument(input); + rootElement.importChild(oldElement); + writeTargets = true; // update the project description + } catch (FileNotFoundException ex) { + /* Ignore */ } } - } - } - protected String getString(Node target, String tagName) { - Node node = searchNode(target, tagName); - return node != null ? (node.getFirstChild() == null ? null : node.getFirstChild().getNodeValue()) : null; - } - - protected Node searchNode(Node target, String tagName) { - NodeList list = target.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - if (list.item(i).getNodeName().equals(tagName)) - return list.item(i); + if (rootElement != null) { + extractMakeTargetsFromDocument(rootElement, manager); + // If write targets then we have converted previous make targets + if (writeTargets) { + saveTargets(); + if (targetFile != null) { + targetFile.delete(); // removed old + } + } + } + } catch (Exception e) { + MakeCorePlugin.log(e); } - return null; } public IMakeTarget[] get(IContainer container) { - ArrayList list = (ArrayList) targetMap.get(container); + List list = targetMap.get(container); if (list != null) { - return (IMakeTarget[]) list.toArray(new IMakeTarget[list.size()]); + return list.toArray(new IMakeTarget[list.size()]); } return new IMakeTarget[0]; } public IMakeTarget findTarget(IContainer container, String name) { - ArrayList list = (ArrayList) targetMap.get(container); + List list = targetMap.get(container); if (list != null) { - Iterator targets = list.iterator(); - while (targets.hasNext()) { - IMakeTarget target = (IMakeTarget) targets.next(); - if (target.getName().equals(name)) { + for (IMakeTarget target : list) { + if (name.equals(target.getName())) { return target; } } @@ -145,20 +121,20 @@ public class ProjectTargets { } public void add(MakeTarget target) throws CoreException { - ArrayList list = (ArrayList) targetMap.get(target.getContainer()); + List list = targetMap.get(target.getContainer()); if (list != null && list.contains(target)) { throw new CoreException(new Status(IStatus.ERROR, MakeCorePlugin.getUniqueIdentifier(), -1, MakeMessages.getString("MakeTargetManager.target_exists"), null)); //$NON-NLS-1$ } if (list == null) { - list = new ArrayList(); + list = new ArrayList(); targetMap.put(target.getContainer(), list); } list.add(target); } public boolean contains(MakeTarget target) { - ArrayList list = (ArrayList) targetMap.get(target.getContainer()); + List list = targetMap.get(target.getContainer()); if (list != null && list.contains(target)) { return true; } @@ -166,7 +142,7 @@ public class ProjectTargets { } public boolean remove(MakeTarget target) { - ArrayList list = (ArrayList) targetMap.get(target.getContainer()); + List list = targetMap.get(target.getContainer()); if (list == null || !list.contains(target)) { return false; } @@ -181,219 +157,138 @@ public class ProjectTargets { return project; } - protected Document getAsXML() throws CoreException { - Document doc; - try { - doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - } catch (ParserConfigurationException ex) { - //This should never happen. - throw new CoreException(new Status(IStatus.ERROR, MakeCorePlugin.getUniqueIdentifier(), -1, - "Error creating new XML storage document", ex)); //$NON-NLS-1$ - } - Element targetsRootElement = doc.createElement(BUILD_TARGET_ELEMENT); - doc.appendChild(targetsRootElement); - Iterator container = targetMap.entrySet().iterator(); - while (container.hasNext()) { - List targets = (List) ((Map.Entry) container.next()).getValue(); - for (int i = 0; i < targets.size(); i++) { - MakeTarget target = (MakeTarget) targets.get(i); - targetsRootElement.appendChild(createTargetElement(doc, target)); - } - } - return doc; - } - - private Node createTargetElement(Document doc, MakeTarget target) { - Element targetElem = doc.createElement(TARGET_ELEMENT); + /** + * Persist the MakeTarget as a child of parent + * @param parent + * @param target + * @return create ICStorageElement + */ + private ICStorageElement createTargetElement(ICStorageElement parent, IMakeTarget target) { + ICStorageElement targetElem = parent.createChild(TARGET_ELEMENT); targetElem.setAttribute(TARGET_ATTR_NAME, target.getName()); targetElem.setAttribute(TARGET_ATTR_ID, target.getTargetBuilderID()); targetElem.setAttribute(TARGET_ATTR_PATH, target.getContainer().getProjectRelativePath().toString()); - Element elem = doc.createElement(TARGET_COMMAND); - targetElem.appendChild(elem); - elem.appendChild(doc.createTextNode(target.getBuildAttribute(IMakeCommonBuildInfo.BUILD_COMMAND, "make"))); //$NON-NLS-1$ + ICStorageElement elem = targetElem.createChild(TARGET_COMMAND); + elem.setValue(target.getBuildAttribute(IMakeCommonBuildInfo.BUILD_COMMAND, "make")); //$NON-NLS-1$ String targetAttr = target.getBuildAttribute(IMakeCommonBuildInfo.BUILD_ARGUMENTS, null); if ( targetAttr != null) { - elem = doc.createElement(TARGET_ARGUMENTS); - elem.appendChild(doc.createTextNode(targetAttr)); - targetElem.appendChild(elem); + elem = targetElem.createChild(TARGET_ARGUMENTS); + elem.setValue(targetAttr); } targetAttr = target.getBuildAttribute(IMakeTarget.BUILD_TARGET, null); if (targetAttr != null) { - elem = doc.createElement(TARGET); - elem.appendChild(doc.createTextNode(targetAttr)); - targetElem.appendChild(elem); + elem = targetElem.createChild(TARGET); + elem.setValue(targetAttr); } - elem = doc.createElement(TARGET_STOP_ON_ERROR); - elem.appendChild(doc.createTextNode(new Boolean(target.isStopOnError()).toString())); - targetElem.appendChild(elem); + elem = targetElem.createChild(TARGET_STOP_ON_ERROR); + elem.setValue(new Boolean(target.isStopOnError()).toString()); + + elem = targetElem.createChild(TARGET_USE_DEFAULT_CMD); + elem.setValue(new Boolean(target.isDefaultBuildCmd()).toString()); + + elem = targetElem.createChild(TARGET_RUN_ALL_BUILDERS); + elem.setValue(new Boolean(target.runAllBuilders()).toString()); - elem = doc.createElement(TARGET_USE_DEFAULT_CMD); - elem.appendChild(doc.createTextNode(new Boolean(target.isDefaultBuildCmd()).toString())); - targetElem.appendChild(elem); - - elem = doc.createElement(TARGET_RUN_ALL_BUILDERS); - elem.appendChild(doc.createTextNode(new Boolean(target.runAllBuilders()).toString())); - targetElem.appendChild(elem); return targetElem; } - public void saveTargets() throws CoreException { - Document doc = getAsXML(); - //Historical method would save the output to the stream specified - //translateDocumentToOutputStream(doc, output); - translateDocumentToCDTProject(doc); - } - - protected void saveTargets(Document doc, OutputStream output) throws TransformerException { - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer; - transformer = factory.newTransformer(); - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ - - DOMSource source = new DOMSource(doc); - StreamResult outputTarget = new StreamResult(output); - transformer.transform(source, outputTarget); - } /** - * This output method saves the information into the .cdtproject metadata file. - * - * @param doc + * Saves the targets to the project description * @throws CoreException */ - protected void translateDocumentToCDTProject(Document doc) throws CoreException { - ICDescriptor descriptor; - descriptor = CCorePlugin.getDefault().getCProjectDescription(getProject(), true); - - Element rootElement = descriptor.getProjectData(MAKE_TARGET_KEY); + public void saveTargets() throws CoreException { + ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(getProject(), true); + ICStorageElement rootElement = descriptor.getProjectStorageElement(MAKE_TARGET_KEY); //Nuke the children since we are going to write out new ones - NodeList kids = rootElement.getChildNodes(); - for (int i = 0; i < kids.getLength(); i++) { - rootElement.removeChild(kids.item(i)); - i--; - } + rootElement.clear(); + + // Fetch the ProjectTargets as ICStorageElements + rootElement = rootElement.createChild(BUILD_TARGET_ELEMENT); + for (Entry> e : targetMap.entrySet()) + for (IMakeTarget target : e.getValue()) + createTargetElement(rootElement, target); - //Extract the root of our temporary document - Node node = doc.getFirstChild(); - if (node.hasChildNodes()) { - //Create a copy which is a part of the new document - Node appendNode = rootElement.getOwnerDocument().importNode(node, true); - //Put the copy into the document in the appropriate location - rootElement.appendChild(appendNode); - } //Save the results descriptor.saveProjectData(); } /** - * This method parses the .cdtproject file for the XML document describing the build targets. - * + * This method loads an old style XML document provided in the input stream + * and returns an ICStorageElemnt wrapping it. * @param input - * @return + * @return ICStorageElement or null */ - protected Document translateCDTProjectToDocument() { - Document document = null; - Element rootElement = null; + protected ICStorageElement translateInputStreamToDocument(InputStream input) { try { - document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - ICDescriptor descriptor; - descriptor = CCorePlugin.getDefault().getCProjectDescription(getProject(), true); - - rootElement = descriptor.getProjectData(MAKE_TARGET_KEY); - } catch (ParserConfigurationException e) { - return document; - } catch (CoreException e) { - return document; - } - NodeList list = rootElement.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - if (list.item(i).getNodeType() == Node.ELEMENT_NODE) { - Node appendNode = document.importNode(list.item(i), true); - document.appendChild(appendNode); - break; // should never have multiple - } - } - return document; - } - - /** - * This method parses the input stream for the XML document describing the build targets. - * - * @param input - * @return - */ - protected Document translateInputStreamToDocument(InputStream input) { - Document document = null; - try { - document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input); + Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input); + return XmlStorageUtil.createCStorageTree(document); } catch (Exception e) { MakeCorePlugin.log(e); } - return document; + return null; } /** * Extract the make target information which is contained in the XML Document - * + * * @param document */ - protected void extractMakeTargetsFromDocument(Document document, MakeTargetManager manager) { - Node node = document.getFirstChild(); - if (node != null && node.getNodeName().equals(BUILD_TARGET_ELEMENT)) { - NodeList list = node.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - node = list.item(i); - if (node.getNodeName().equals(TARGET_ELEMENT)) { - IContainer container = null; - NamedNodeMap attr = node.getAttributes(); - String path = attr.getNamedItem(TARGET_ATTR_PATH).getNodeValue(); - if (path != null && !path.equals("")) { //$NON-NLS-1$ - container = project.getFolder(path); - } else { - container = project; - } - try { - MakeTarget target = new MakeTarget(manager, project, attr.getNamedItem(TARGET_ATTR_ID).getNodeValue(), - attr.getNamedItem(TARGET_ATTR_NAME).getNodeValue()); - target.setContainer(container); - String option = getString(node, TARGET_STOP_ON_ERROR); - if (option != null) { - target.setStopOnError(Boolean.valueOf(option).booleanValue()); + protected void extractMakeTargetsFromDocument(ICStorageElement root, MakeTargetManager manager) { + for (ICStorageElement node : root.getChildren()) { + if (node.getName().equals(BUILD_TARGET_ELEMENT)) { + for (ICStorageElement child : node.getChildren()) { + node = child; + if (node.getName().equals(TARGET_ELEMENT)) { + IContainer container = null; + String path = node.getAttribute(TARGET_ATTR_PATH); + if (path != null && !path.equals("")) { //$NON-NLS-1$ + container = project.getFolder(path); + } else { + container = project; } - option = getString(node, TARGET_USE_DEFAULT_CMD); - if (option != null) { - target.setUseDefaultBuildCmd(Boolean.valueOf(option).booleanValue()); + try { + MakeTarget target = new MakeTarget(manager, project, node.getAttribute(TARGET_ATTR_ID), + node.getAttribute(TARGET_ATTR_NAME)); + target.setContainer(container); + ICStorageElement[] option = node.getChildrenByName(TARGET_STOP_ON_ERROR); + if (option.length > 0) { + target.setStopOnError(Boolean.valueOf(option[0].getValue()).booleanValue()); + } + option = node.getChildrenByName(TARGET_USE_DEFAULT_CMD); + if (option.length > 0) { + target.setUseDefaultBuildCmd(Boolean.valueOf(option[0].getValue()).booleanValue()); + } + option = node.getChildrenByName(TARGET_COMMAND); + if (option.length > 0) { + target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_COMMAND, option[0].getValue()); + } + option = node.getChildrenByName(TARGET_ARGUMENTS); + if (option.length > 0) { + target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_ARGUMENTS, option[0].getValue()); + } else if (!target.isDefaultBuildCmd()) { + // Clear build-arguments set in target constructor to project defaults + target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_ARGUMENTS, ""); //$NON-NLS-1$ + } + option = node.getChildrenByName(BAD_TARGET); + if (option.length > 0) { + target.setBuildAttribute(IMakeTarget.BUILD_TARGET, option[0].getValue()); + } + option = node.getChildrenByName(TARGET); + if (option.length > 0) { + target.setBuildAttribute(IMakeTarget.BUILD_TARGET, option[0].getValue()); + } + option = node.getChildrenByName(TARGET_RUN_ALL_BUILDERS); + if (option.length > 0) { + target.setRunAllBuilders(Boolean.valueOf(option[0].getValue()).booleanValue()); + } + add(target); + } catch (CoreException e) { + MakeCorePlugin.log(e); } - option = getString(node, TARGET_COMMAND); - if (option != null) { - target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_COMMAND, option); - } - option = getString(node, TARGET_ARGUMENTS); - if (option != null) { - target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_ARGUMENTS, option); - } else if (!target.isDefaultBuildCmd()) { - // Clear build-arguments set in target constructor to project defaults - target.setBuildAttribute(IMakeCommonBuildInfo.BUILD_ARGUMENTS, ""); //$NON-NLS-1$ - } - option = getString(node, BAD_TARGET); - if (option != null) { - target.setBuildAttribute(IMakeTarget.BUILD_TARGET, option); - } - option = getString(node, TARGET); - if (option != null) { - target.setBuildAttribute(IMakeTarget.BUILD_TARGET, option); - } - option = getString(node, TARGET_RUN_ALL_BUILDERS); - if (option != null) { - target.setRunAllBuilders(Boolean.valueOf(option).booleanValue()); - } - add(target); - } catch (CoreException e) { - MakeCorePlugin.log(e); } } } diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/PerProjectSICollector.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/PerProjectSICollector.java index dd5faef410a..733a693942a 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/PerProjectSICollector.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/PerProjectSICollector.java @@ -365,7 +365,7 @@ public class PerProjectSICollector implements IScannerInfoCollector3, IScannerIn /* (non-Javadoc) * @see org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector2#getDefinedSymbols() */ - public Map getDefinedSymbols() { + public Map getDefinedSymbols() { Map definedSymbols = ScannerConfigUtil.scSymbolEntryMap2Map(sumDiscoveredSymbols); return definedSymbols; } diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/ScannerConfigInfoFactory2.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/ScannerConfigInfoFactory2.java index a5eb0e4e4c7..7d43100c31a 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/ScannerConfigInfoFactory2.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/ScannerConfigInfoFactory2.java @@ -7,6 +7,7 @@ * * Contributors: * IBM - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.make.internal.core.scannerconfig2; @@ -22,6 +23,7 @@ import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ICDescriptor; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.make.core.MakeCorePlugin; import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo; @@ -35,9 +37,6 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Preferences; import org.eclipse.core.runtime.Status; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; /** * New ScannerConfigInfoFactory @@ -93,31 +92,29 @@ public class ScannerConfigInfoFactory2 { load(profileId); } - private void load(String profileId) { + private void load(String profileId) { ICDescriptor descriptor; try { descriptor = CCorePlugin.getDefault().getCProjectDescription(fProject, false); - Element rootEl = descriptor != null ? descriptor.getProjectData(SCANNER_CONFIG) : null; + ICStorageElement rootEl = descriptor != null ? descriptor.getProjectStorageElement(SCANNER_CONFIG) : null; InfoContext defaultContext = new InfoContext(fProject); - if(rootEl == null || !rootEl.hasChildNodes()){ + if(rootEl == null || !rootEl.hasChildren()){ BuildProperty prop = new BuildProperty(this, fProject, defaultContext, (Store)create(MakeCorePlugin.getDefault().getPluginPreferences(), profileId, false), profileId); fMap.put(defaultContext, prop); prop.isDirty = true; } else { - BuildProperty prop = new BuildProperty(this, fProject,defaultContext, profileId, rootEl); + BuildProperty prop = new BuildProperty(this, fProject, defaultContext, profileId, rootEl); fMap.put(defaultContext, prop); - - for (Node sc = rootEl.getFirstChild(); - sc != null; sc = sc.getNextSibling()) { - if (sc.getNodeName().equals(ELEMENT_CS_INFO)) { - Element el = (Element)sc; - String instanceId = el.getAttribute(ATTRIBUTE_CS_INFO_INSTANCE_ID); - if(instanceId.length() != 0){ - InfoContext c = new InfoContext(fProject, instanceId); - BuildProperty p = new BuildProperty(this, fProject, c, profileId, el); - fMap.put(c, p); - } - } + + for (ICStorageElement sc : rootEl.getChildren()) { + if (sc.getName().equals(ELEMENT_CS_INFO)) { + String instanceId = sc.getAttribute(ATTRIBUTE_CS_INFO_INSTANCE_ID); + if(instanceId != null && instanceId.length() > 0){ + InfoContext c = new InfoContext(fProject, instanceId); + BuildProperty p = new BuildProperty(this, fProject, c, profileId, sc); + fMap.put(c, p); + } + } } } } catch (CoreException e) { @@ -132,16 +129,10 @@ public class ScannerConfigInfoFactory2 { public void save(boolean serializeDescriptor) throws CoreException { if (isDirty()) { ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element sc = descriptor.getProjectData(SCANNER_CONFIG); + ICStorageElement sc = descriptor.getProjectStorageElement(SCANNER_CONFIG); - Document doc = sc.getOwnerDocument(); - - // Clear out all current children - Node child = sc.getFirstChild(); - while (child != null) { - sc.removeChild(child); - child = sc.getFirstChild(); - } + // Clear all child settings + sc.clear(); BuildProperty prop = (BuildProperty)fMap.get(new InfoContext(fProject)); prop.store(sc); @@ -161,10 +152,9 @@ public class ScannerConfigInfoFactory2 { if(p == prop) continue; - Element el = doc.createElement(ELEMENT_CS_INFO); + ICStorageElement el = sc.createChild(ELEMENT_CS_INFO); el.setAttribute(ATTRIBUTE_CS_INFO_INSTANCE_ID, instanceId); p.store(el); - sc.appendChild(el); } if(serializeDescriptor) @@ -218,7 +208,7 @@ public class ScannerConfigInfoFactory2 { public void save() throws CoreException { if (isDirty()) { - Set idSet = new HashSet(fMap.size() - 1); + Set idSet = new HashSet(fMap.size() - 1); Preference pref = (Preference)fMap.get(new InfoContext(null)); pref.store(); @@ -244,7 +234,7 @@ public class ScannerConfigInfoFactory2 { } if(idSet.size() != 0){ - String[] ids = (String[])idSet.toArray(new String[idSet.size()]); + String[] ids = idSet.toArray(new String[idSet.size()]); String idsString = CDataUtil.arrayToString(ids, DELIMITER); set(INFO_INSTANCE_IDS, idsString); } @@ -281,7 +271,7 @@ public class ScannerConfigInfoFactory2 { private static abstract class StoreSet implements IScannerConfigBuilderInfo2Set { - protected HashMap fMap = new HashMap(); + protected HashMap fMap = new HashMap(); protected boolean fIsDirty; StoreSet(){ @@ -304,21 +294,21 @@ public class ScannerConfigInfoFactory2 { } public InfoContext[] getContexts() { - return (InfoContext[])fMap.keySet().toArray(new InfoContext[fMap.size()]); + return fMap.keySet().toArray(new InfoContext[fMap.size()]); } public IScannerConfigBuilderInfo2 getInfo(InfoContext context) { - return (IScannerConfigBuilderInfo2)fMap.get(context); + return fMap.get(context); } - public Map getInfoMap() { + public Map getInfoMap() { return Collections.unmodifiableMap(fMap); } public IScannerConfigBuilderInfo2 removeInfo(InfoContext context) throws CoreException { checkRemoveInfo(context); fIsDirty = true; - return (IScannerConfigBuilderInfo2)fMap.remove(context); + return fMap.remove(context); } private void checkRemoveInfo(InfoContext context) throws CoreException{ @@ -329,8 +319,8 @@ public class ScannerConfigInfoFactory2 { public boolean isDirty(){ if(fIsDirty) return true; - for(Iterator iter = fMap.values().iterator(); iter.hasNext();){ - Store prop = (Store)iter.next(); + for(Iterator iter = fMap.values().iterator(); iter.hasNext();){ + Store prop = iter.next(); if(prop.isDirty) return true; } @@ -358,12 +348,14 @@ public class ScannerConfigInfoFactory2 { protected boolean autoDiscoveryEnabled; protected boolean problemReportingEnabled; protected String selectedProfile = EMPTY_STRING; - protected Map profileOptionsMap; // (profileId, options) + /** Map from profile ID -> ProfileOptions */ + protected Map profileOptionsMap; static class ProfileOptions { protected boolean buildOutputFileActionEnabled; protected String buildOutputFilePath = EMPTY_STRING; protected boolean buildOutputParserEnabled; - protected Map providerOptionsMap; // {providerId, options} + /** Map from provider ID -> providerOptions */ + protected Map providerOptionsMap; static class ProviderOptions { protected String providerKind; // derived protected boolean providerOutputParserEnabled; @@ -393,10 +385,9 @@ public class ScannerConfigInfoFactory2 { this.buildOutputFileActionEnabled = base.buildOutputFileActionEnabled; this.buildOutputFilePath = base.buildOutputFilePath; this.buildOutputParserEnabled = base.buildOutputParserEnabled; - this.providerOptionsMap = new LinkedHashMap(base.providerOptionsMap); - for(Iterator iter = this.providerOptionsMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); - ProviderOptions basePo = (ProviderOptions)entry.getValue(); + this.providerOptionsMap = new LinkedHashMap(base.providerOptionsMap); + for (Map.Entry entry : providerOptionsMap.entrySet()) { + ProviderOptions basePo = entry.getValue(); entry.setValue(new ProviderOptions(basePo)); } } @@ -411,10 +402,9 @@ public class ScannerConfigInfoFactory2 { this.autoDiscoveryEnabled = base.autoDiscoveryEnabled; this.problemReportingEnabled = base.problemReportingEnabled; this.selectedProfile = ScannerConfigProfileManager.NULL_PROFILE_ID.equals(profileId) ? base.selectedProfile : profileId; - this.profileOptionsMap = new LinkedHashMap(base.profileOptionsMap); - for(Iterator iter = this.profileOptionsMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); - ProfileOptions basePo = (ProfileOptions)entry.getValue(); + this.profileOptionsMap = new LinkedHashMap(base.profileOptionsMap); + for (Map.Entry entry : profileOptionsMap.entrySet()) { + ProfileOptions basePo = entry.getValue(); entry.setValue(new ProfileOptions(basePo)); } @@ -473,15 +463,15 @@ public class ScannerConfigInfoFactory2 { /* (non-Javadoc) * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#getProfileIdList() */ - public List getProfileIdList() { - return new ArrayList(profileOptionsMap.keySet()); + public List getProfileIdList() { + return new ArrayList(profileOptionsMap.keySet()); } /* (non-Javadoc) * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#isBuildOutputFileActionEnabled() */ public boolean isBuildOutputFileActionEnabled() { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); return (po != null) ? po.buildOutputFileActionEnabled : false; } @@ -489,7 +479,7 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setBuildOutputFileActionEnabled(boolean) */ public void setBuildOutputFileActionEnabled(boolean enable) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { po.buildOutputFileActionEnabled = setDirty(po.buildOutputFileActionEnabled, enable); } @@ -499,7 +489,7 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#getBuildOutputFilePath() */ public String getBuildOutputFilePath() { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); return (po != null) ? po.buildOutputFilePath : EMPTY_STRING; } @@ -507,7 +497,7 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setBuildOutputFilePath(java.lang.String) */ public void setBuildOutputFilePath(String path) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { po.buildOutputFilePath = setDirty(po.buildOutputFilePath, path); } @@ -517,7 +507,7 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#isBuildOutputParserEnabled() */ public boolean isBuildOutputParserEnabled() { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); return (po != null) ? po.buildOutputParserEnabled : true; } @@ -525,7 +515,7 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setBuildOutputParserEnabled(boolean) */ public void setBuildOutputParserEnabled(boolean enable) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { po.buildOutputParserEnabled = setDirty(po.buildOutputParserEnabled, enable); } @@ -536,7 +526,7 @@ public class ScannerConfigInfoFactory2 { */ @SuppressWarnings("unchecked") public List getProviderIdList() { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); return (po != null) ? new ArrayList(po.providerOptionsMap.keySet()) : new ArrayList(0); } @@ -558,9 +548,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#isSIProviderOutputParserEnabled(java.lang.String) */ public boolean isProviderOutputParserEnabled(String providerId) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); return (ppo == null) ? false : ppo.providerOutputParserEnabled; } return false; @@ -570,9 +560,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setSIProviderOutputParserEnabled(java.lang.String, boolean) */ public void setProviderOutputParserEnabled(String providerId, boolean enable) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { ppo.providerOutputParserEnabled = setDirty(ppo.providerOutputParserEnabled, enable); } @@ -583,9 +573,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#isUseDefaultProviderCommand(java.lang.String) */ public boolean isUseDefaultProviderCommand(String providerId) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); return (ppo == null) ? false : ppo.providerRunUseDefault; } return false; @@ -595,9 +585,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setUseDefaultProviderCommand(java.lang.String, boolean) */ public void setUseDefaultProviderCommand(String providerId, boolean enable) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { ppo.providerRunUseDefault = setDirty(ppo.providerRunUseDefault, enable); } @@ -608,9 +598,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#getProviderRunCommand(java.lang.String) */ public String getProviderRunCommand(String providerId) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); return (ppo == null) ? null : ppo.providerRunCommand; } return null; @@ -620,9 +610,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setProviderRunCommand(java.lang.String, java.lang.String) */ public void setProviderRunCommand(String providerId, String command) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { ppo.providerRunCommand = setDirty(ppo.providerRunCommand, command); } @@ -633,9 +623,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#getProviderRunArguments(java.lang.String) */ public String getProviderRunArguments(String providerId) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); return (ppo == null) ? null : ppo.providerRunArguments; } return null; @@ -645,9 +635,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setProviderRunArguments(java.lang.String, java.lang.String) */ public void setProviderRunArguments(String providerId, String arguments) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { ppo.providerRunArguments = setDirty(ppo.providerRunArguments, arguments); } @@ -658,9 +648,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#getProviderOpenFilePath(java.lang.String) */ public String getProviderOpenFilePath(String providerId) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); return (ppo == null) ? null : ppo.providerOpenFilePath; } return null; @@ -670,9 +660,9 @@ public class ScannerConfigInfoFactory2 { * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2#setProviderOpenFilePath(java.lang.String, java.lang.String) */ public void setProviderOpenFilePath(String providerId, String filePath) { - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(selectedProfile); + ProfileOptions po = profileOptionsMap.get(selectedProfile); if (po != null) { - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { ppo.providerOpenFilePath = setDirty(ppo.providerOpenFilePath, filePath); } @@ -711,7 +701,7 @@ public class ScannerConfigInfoFactory2 { po.buildOutputFilePath = (buildOutputFilePath != null) ? buildOutputFilePath : EMPTY_STRING; } } - po.providerOptionsMap = new LinkedHashMap(providerIds.size()); + po.providerOptionsMap = new LinkedHashMap(providerIds.size()); for (int i = 0; i < providerIds.size(); ++i) { ProfileOptions.ProviderOptions ppo = new ProfileOptions.ProviderOptions(); String providerId = (String) providerIds.get(i); @@ -751,7 +741,7 @@ public class ScannerConfigInfoFactory2 { private String profileId; private ScannerConfigInfoSet container; - BuildProperty(ScannerConfigInfoSet container, IProject project, InfoContext context, String profileId, Element element) { + BuildProperty(ScannerConfigInfoSet container, IProject project, InfoContext context, String profileId, ICStorageElement element) { super(); this.project = project; this.context = context; @@ -779,27 +769,26 @@ public class ScannerConfigInfoFactory2 { /* (non-Javadoc) * @see org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigInfoFactory2.Store#load() */ - protected void load(Element element) { + protected void load(ICStorageElement element) { // ICDescriptor descriptor; - List profileIds = ScannerConfigProfileManager.getInstance().getProfileIds(context); - List loadedProfiles = new ArrayList(); + List profileIds = ScannerConfigProfileManager.getInstance().getProfileIds(context); + List loadedProfiles = new ArrayList(); // try { // descriptor = CCorePlugin.getDefault().getCProjectDescription(project, false); - for (Node sc = element.getFirstChild(); - sc != null; sc = sc.getNextSibling()) { - if (sc.getNodeName().equals(SC_AUTODISCOVERY)) { + for (ICStorageElement sc : element.getChildren()) { + if (sc.getName().equals(SC_AUTODISCOVERY)) { autoDiscoveryEnabled = Boolean.valueOf( - ((Element)sc).getAttribute(ENABLED)).booleanValue(); + sc.getAttribute(ENABLED)).booleanValue(); selectedProfile = (profileId == ScannerConfigProfileManager.NULL_PROFILE_ID) - ? ((Element)sc).getAttribute(SELECTED_PROFILE_ID) + ? sc.getAttribute(SELECTED_PROFILE_ID) : profileId; problemReportingEnabled = Boolean.valueOf( - ((Element)sc).getAttribute(PROBLEM_REPORTING_ENABLED)).booleanValue(); + sc.getAttribute(PROBLEM_REPORTING_ENABLED)).booleanValue(); } - else if (sc.getNodeName().equals(PROFILE)) { - if (profileIds.contains(((Element)sc).getAttribute(ID))) { - load(sc); - loadedProfiles.add(((Element)sc).getAttribute(ID)); + else if (sc.getName().equals(PROFILE)) { + if (profileIds.contains(sc.getAttribute(ID))) { + loadProfile(sc); + loadedProfiles.add(sc.getAttribute(ID)); } } } @@ -844,7 +833,7 @@ public class ScannerConfigInfoFactory2 { ScannerConfigProfile configuredProfile = ScannerConfigProfileManager.getInstance(). getSCProfileConfiguration(profileId); - po.providerOptionsMap = new LinkedHashMap(); + po.providerOptionsMap = new LinkedHashMap(); for (Iterator i = configuredProfile.getSIProviderIds().iterator(); i.hasNext(); ) { String providerId = (String) i.next(); ProfileOptions.ProviderOptions ppo = new ProfileOptions.ProviderOptions(); @@ -865,7 +854,7 @@ public class ScannerConfigInfoFactory2 { } if (profileOptionsMap == null) { - profileOptionsMap = new LinkedHashMap(); + profileOptionsMap = new LinkedHashMap(); } profileOptionsMap.put(profileId, po); } @@ -898,10 +887,10 @@ public class ScannerConfigInfoFactory2 { getSCProfileConfiguration(selectedProfile); // get the one and only provider id String providerId = (String) configuredProfile.getSIProviderIds().get(0); - po.providerOptionsMap = new LinkedHashMap(1); + po.providerOptionsMap = new LinkedHashMap(1); po.providerOptionsMap.put(providerId, ppo); - profileOptionsMap = new LinkedHashMap(1); + profileOptionsMap = new LinkedHashMap(1); profileOptionsMap.put(profileId, po); // store migrated data @@ -918,42 +907,37 @@ public class ScannerConfigInfoFactory2 { /** * @param profile */ - private void load(Node profile) { + private void loadProfile(ICStorageElement profile) { if (profileOptionsMap == null) { - profileOptionsMap = new LinkedHashMap(1); + profileOptionsMap = new LinkedHashMap(1); } ProfileOptions po = new ProfileOptions(); - String profileId = ((Element)profile).getAttribute(ID); + String profileId = profile.getAttribute(ID); profileOptionsMap.put(profileId, po); // get the list of providers from the profile configuration ScannerConfigProfile configuredProfile = ScannerConfigProfileManager.getInstance(). getSCProfileConfiguration(profileId); - List providerIds = configuredProfile.getSIProviderIds(); + List providerIds = configuredProfile.getSIProviderIds(); int providerCounter = 0; - po.providerOptionsMap = new LinkedHashMap(providerIds.size()); + po.providerOptionsMap = new LinkedHashMap(providerIds.size()); - for (Node child = profile.getFirstChild(); - child != null; - child = child.getNextSibling()) { + for (ICStorageElement child : profile.getChildren()) { // buildOutputProvider element - if (BUILD_OUTPUT_PROVIDER.equals(child.getNodeName())) { - for (Node grandchild = child.getFirstChild(); - grandchild != null; - grandchild = grandchild.getNextSibling()) { - - if (OPEN_ACTION.equals(grandchild.getNodeName())) { + if (BUILD_OUTPUT_PROVIDER.equals(child.getName())) { + for (ICStorageElement grandchild : child.getChildren()) { + if (OPEN_ACTION.equals(grandchild.getName())) { po.buildOutputFileActionEnabled = Boolean.valueOf( - ((Element)grandchild).getAttribute(ENABLED)).booleanValue(); - po.buildOutputFilePath = ((Element)grandchild).getAttribute(FILE_PATH); + grandchild.getAttribute(ENABLED)).booleanValue(); + po.buildOutputFilePath = grandchild.getAttribute(FILE_PATH); } - else if (PARSER.equals(grandchild.getNodeName())) { + else if (PARSER.equals(grandchild.getName())) { po.buildOutputParserEnabled = Boolean.valueOf( - ((Element)grandchild).getAttribute(ENABLED)).booleanValue(); + grandchild.getAttribute(ENABLED)).booleanValue(); } } } - else if (SCANNER_INFO_PROVIDER.equals(child.getNodeName())) { - String providerId = ((Element)child).getAttribute(ID); + else if (SCANNER_INFO_PROVIDER.equals(child.getName())) { + String providerId = child.getAttribute(ID); if (providerIds.get(providerCounter).equals(providerId)) { // new provider ProfileOptions.ProviderOptions ppo = new ProfileOptions.ProviderOptions(); @@ -961,23 +945,21 @@ public class ScannerConfigInfoFactory2 { ppo.providerKind = configuredProfile.getScannerInfoProviderElement( providerId).getProviderKind(); - for (Node grandchild = child.getFirstChild(); - grandchild != null; - grandchild = grandchild.getNextSibling()) { + for (ICStorageElement grandchild : child.getChildren()) { // action - if (RUN_ACTION.equals(grandchild.getNodeName())) { + if (RUN_ACTION.equals(grandchild.getName())) { ppo.providerRunUseDefault = Boolean.valueOf( - ((Element)grandchild).getAttribute(USE_DEFAULT)).booleanValue(); - ppo.providerRunCommand = ((Element)grandchild).getAttribute(COMMAND); - ppo.providerRunArguments = ((Element)grandchild).getAttribute(ARGUMENTS); + grandchild.getAttribute(USE_DEFAULT)).booleanValue(); + ppo.providerRunCommand = grandchild.getAttribute(COMMAND); + ppo.providerRunArguments = grandchild.getAttribute(ARGUMENTS); } - else if (OPEN_ACTION.equals(grandchild.getNodeName())) { - ppo.providerOpenFilePath = ((Element)grandchild).getAttribute(FILE_PATH); + else if (OPEN_ACTION.equals(grandchild.getName())) { + ppo.providerOpenFilePath = grandchild.getAttribute(FILE_PATH); } // parser - else if (PARSER.equals(grandchild.getNodeName())) { + else if (PARSER.equals(grandchild.getName())) { ppo.providerOutputParserEnabled = Boolean.valueOf( - ((Element)grandchild).getAttribute(ENABLED)).booleanValue(); + grandchild.getAttribute(ENABLED)).booleanValue(); } } ++providerCounter; @@ -990,31 +972,25 @@ public class ScannerConfigInfoFactory2 { } } - private void store(Element sc)/* throws CoreException */{ + private void store(ICStorageElement sc)/* throws CoreException */{ // if (isDirty || force) { // ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project, true); // Element sc = descriptor.getProjectData(SCANNER_CONFIG); - Document doc = sc.getOwnerDocument(); - // Clear out all current children - Node child = sc.getFirstChild(); - while (child != null) { - sc.removeChild(child); - child = sc.getFirstChild(); - } + // Clear children + for (ICStorageElement child : sc.getChildren()) + sc.removeChild(child); - Element autod = doc.createElement(SC_AUTODISCOVERY); - sc.appendChild(autod); + ICStorageElement autod = sc.createChild(SC_AUTODISCOVERY); autod.setAttribute(ENABLED, Boolean.toString(autoDiscoveryEnabled)); autod.setAttribute(SELECTED_PROFILE_ID, selectedProfile); autod.setAttribute(PROBLEM_REPORTING_ENABLED, Boolean.toString(problemReportingEnabled)); - for (Iterator i = profileOptionsMap.keySet().iterator(); i.hasNext();) { - String profileId = (String) i.next(); - Element profile = doc.createElement(PROFILE); + for (Iterator i = profileOptionsMap.keySet().iterator(); i.hasNext();) { + String profileId = i.next(); + ICStorageElement profile = sc.createChild(PROFILE); profile.setAttribute(ID, profileId); - store(profile, (ProfileOptions) profileOptionsMap.get(profileId)); - sc.appendChild(profile); + store(profile, profileOptionsMap.get(profileId)); } isDirty = false; @@ -1027,32 +1003,28 @@ public class ScannerConfigInfoFactory2 { * @param profile element * @param profile options */ - private void store(Element profile, ProfileOptions po) { - Element child, grandchild; - Document doc = profile.getOwnerDocument(); + private void store(ICStorageElement profile, ProfileOptions po) { + ICStorageElement child, grandchild; // buildOutputProvider element - child = doc.createElement(BUILD_OUTPUT_PROVIDER); - grandchild = doc.createElement(OPEN_ACTION); + child = profile.createChild(BUILD_OUTPUT_PROVIDER); + grandchild = child.createChild(OPEN_ACTION); grandchild.setAttribute(ENABLED, Boolean.toString(po.buildOutputFileActionEnabled)); if(po.buildOutputFilePath != null) grandchild.setAttribute(FILE_PATH, po.buildOutputFilePath); - child.appendChild(grandchild); - grandchild = doc.createElement(PARSER); + grandchild = child.createChild(PARSER); grandchild.setAttribute(ENABLED, Boolean.toString(po.buildOutputParserEnabled)); - child.appendChild(grandchild); - profile.appendChild(child); // scannerInfoProvider elements // get the list of providers from the profile configuration // ScannerConfigProfile configuredProfile = ScannerConfigProfileManager.getInstance(). // getSCProfileConfiguration(selectedProfile); // List providerIds = configuredProfile.getSIProviderIds(); - List providerIds = new ArrayList(po.providerOptionsMap.keySet()); + List providerIds = new ArrayList(po.providerOptionsMap.keySet()); for (int i = 0; i < providerIds.size(); ++i) { - String providerId = (String) providerIds.get(i); - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) po.providerOptionsMap.get(providerId); + String providerId = providerIds.get(i); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); if (ppo != null) { - child = doc.createElement(SCANNER_INFO_PROVIDER); + child = profile.createChild(SCANNER_INFO_PROVIDER); child.setAttribute(ID, providerId); // action @@ -1061,7 +1033,7 @@ public class ScannerConfigInfoFactory2 { String providerKind = ppo.providerKind; if (providerKind.equals(ScannerConfigProfile.ScannerInfoProvider.RUN)) { - grandchild = doc.createElement(RUN_ACTION); + grandchild = child.createChild(RUN_ACTION); grandchild.setAttribute(USE_DEFAULT, Boolean.toString(ppo.providerRunUseDefault)); if(ppo.providerRunCommand != null) grandchild.setAttribute(COMMAND, ppo.providerRunCommand); @@ -1069,16 +1041,13 @@ public class ScannerConfigInfoFactory2 { grandchild.setAttribute(ARGUMENTS, ppo.providerRunArguments); } else if (providerKind.equals(ScannerConfigProfile.ScannerInfoProvider.OPEN)) { - grandchild = doc.createElement(OPEN_ACTION); + grandchild = child.createChild(OPEN_ACTION); if(ppo.providerOpenFilePath != null) grandchild.setAttribute(FILE_PATH, ppo.providerOpenFilePath); } - child.appendChild(grandchild); // parser - grandchild = doc.createElement(PARSER); + grandchild = child.createChild(PARSER); grandchild.setAttribute(ENABLED, Boolean.toString(ppo.providerOutputParserEnabled)); - child.appendChild(grandchild); - profile.appendChild(child); } else { // missing provider options - error @@ -1095,17 +1064,6 @@ public class ScannerConfigInfoFactory2 { container.save(true); isDirty = false; } -// if (store()) { -// ICDescriptorOperation op = new ICDescriptorOperation() { -// -// public void execute(ICDescriptor descriptor, IProgressMonitor monitor) throws CoreException { -// descriptor.saveProjectData(); -// } -// -// }; -// CCorePlugin.getDefault().getCDescriptorManager(). -// runDescriptorOperation(project, op, null); -// } } public InfoContext getContext(){ @@ -1176,7 +1134,7 @@ public class ScannerConfigInfoFactory2 { selectedProfile = prefs.getDefaultString(prefix + SCANNER_CONFIG_SELECTED_PROFILE_ID_SUFFIX); } List profileIds = ScannerConfigProfileManager.getInstance().getProfileIds(context); - profileOptionsMap = new LinkedHashMap(profileIds.size()); + profileOptionsMap = new LinkedHashMap(profileIds.size()); for (Iterator I = profileIds.iterator(); I.hasNext(); ) { String profileId = (String) I.next(); ProfileOptions po = new ProfileOptions(); @@ -1195,7 +1153,7 @@ public class ScannerConfigInfoFactory2 { ScannerConfigProfile configuredProfile = ScannerConfigProfileManager.getInstance(). getSCProfileConfiguration(profileId); List providerIds = configuredProfile.getSIProviderIds(); - po.providerOptionsMap = new LinkedHashMap(providerIds.size()); + po.providerOptionsMap = new LinkedHashMap(providerIds.size()); for (int i = 0; i < providerIds.size(); ++i) { String providerId = (String) providerIds.get(i); ProfileOptions.ProviderOptions ppo = new ProfileOptions.ProviderOptions(); @@ -1229,10 +1187,10 @@ public class ScannerConfigInfoFactory2 { set(prefix + SCANNER_CONFIG_SELECTED_PROFILE_ID_SUFFIX, selectedProfile); set(prefix + SCANNER_CONFIG_PROBLEM_REPORTING_ENABLED_SUFFIX, problemReportingEnabled); - List profileIds = new ArrayList(profileOptionsMap.keySet()); - for (Iterator I = profileIds.iterator(); I.hasNext(); ) { - String profileId = (String) I.next(); - ProfileOptions po = (ProfileOptions) profileOptionsMap.get(profileId); + List profileIds = new ArrayList(profileOptionsMap.keySet()); + for (Iterator I = profileIds.iterator(); I.hasNext(); ) { + String profileId = I.next(); + ProfileOptions po = profileOptionsMap.get(profileId); set(SCD + prefix + profileId + DOT + ENABLED, !useDefaults); set(SCD + prefix + profileId + BUILD_OUTPUT_OPEN_ACTION_ENABLED, po.buildOutputFileActionEnabled); @@ -1244,8 +1202,7 @@ public class ScannerConfigInfoFactory2 { List providerIds = configuredProfile.getSIProviderIds(); for (int i = 0; i < providerIds.size(); ++i) { String providerId = (String) providerIds.get(i); - ProfileOptions.ProviderOptions ppo = (ProfileOptions.ProviderOptions) - po.providerOptionsMap.get(providerId); + ProfileOptions.ProviderOptions ppo = po.providerOptionsMap.get(providerId); set(SCD + prefix + profileId + DOT + providerId + SI_PROVIDER_PARSER_ENABLED, ppo.providerOutputParserEnabled); diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF index 46c70d7d866..b381a5bcf23 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.ui, org.eclipse.ui.ide, org.eclipse.cdt.core, - org.eclipse.cdt.managedbuilder.core + org.eclipse.cdt.managedbuilder.core, + org.eclipse.cdt.core.tests;bundle-version="5.0.0" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java index 267a50613b5..d7f8e2ad82a 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java @@ -8,12 +8,14 @@ * Contributors: * IBM - Initial API and implementation * Markus Schorn (Wind River Systems) + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.tests.suite; import junit.framework.Test; import junit.framework.TestSuite; +import org.eclipse.cdt.build.core.scannerconfig.tests.CfgScannerConfigProfileManagerTests; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.managedbuilder.core.tests.BuildDescriptionModelTests; @@ -32,28 +34,28 @@ import org.eclipse.cdt.managedbuilder.core.tests.MultiVersionSupportTests; import org.eclipse.cdt.managedbuilder.core.tests.OptionEnablementTests; import org.eclipse.cdt.managedbuilder.core.tests.PathConverterTest; import org.eclipse.cdt.managedbuilder.core.tests.ResourceBuildCoreTests; +import org.eclipse.cdt.managedbuilder.templateengine.tests.AllTemplateEngineTests; import org.eclipse.cdt.projectmodel.tests.BackwardCompatiblityTests; import org.eclipse.cdt.projectmodel.tests.CProjectDescriptionSerializationTests; import org.eclipse.cdt.projectmodel.tests.OptionStringListValueTests; import org.eclipse.cdt.projectmodel.tests.ProjectModelTests; /** - * + * Main TestSuite for all the managed build tests */ public class AllManagedBuildTests { public static void main(String[] args) { junit.textui.TestRunner.run(AllManagedBuildTests.suite()); } public static Test suite() { - // May/2005 Turning off all indexing for now because the "original" indexer causes hangs... - CCorePlugin.getDefault().getPluginPreferences().setValue(CCorePlugin.PREF_INDEXER, IPDOMManager.ID_NO_INDEXER); - // We could enable this later... - //CCorePlugin.getDefault().getPluginPreferences().setValue(CCorePlugin.PREF_INDEXER, IPDOMManager.ID_FULL_INDEXER); + CCorePlugin.getDefault().getPluginPreferences().setValue(CCorePlugin.PREF_INDEXER, IPDOMManager.ID_FAST_INDEXER); - TestSuite suite = new TestSuite( - "Test for org.eclipse.cdt.managedbuild.core.tests"); + TestSuite suite = new TestSuite("Test for org.eclipse.cdt.managedbuild.core.tests"); //$JUnit-BEGIN$ -// TODO uncoment this + // build.core.scannerconfig.tests + suite.addTest(CfgScannerConfigProfileManagerTests.suite()); + + // managedbuilder.core.tests suite.addTest(ManagedBuildCoreTests20.suite()); suite.addTest(ManagedBuildCoreTests.suite()); suite.addTest(ManagedProjectUpdateTests.suite()); @@ -68,13 +70,17 @@ public class AllManagedBuildTests { suite.addTest(MultiVersionSupportTests.suite()); suite.addTest(OptionEnablementTests.suite()); suite.addTest(ManagedBuildDependencyCalculatorTests.suite()); - suite.addTest(BuildDescriptionModelTests.suite()); suite.addTest(PathConverterTest.suite()); - suite.addTest(ProjectModelTests.suite()); - suite.addTest(OptionStringListValueTests.suite()); + + // managedbuilder.templateengine.tests + suite.addTest(AllTemplateEngineTests.suite()); + + // projectmodel.tests suite.addTest(BackwardCompatiblityTests.suite()); suite.addTest(CProjectDescriptionSerializationTests.suite()); + suite.addTest(OptionStringListValueTests.suite()); + suite.addTest(ProjectModelTests.suite()); //$JUnit-END$ return suite; } diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/CfgScannerConfigProfileManagerTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/CfgScannerConfigProfileManagerTests.java new file mode 100644 index 00000000000..a68c9d730ef --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/CfgScannerConfigProfileManagerTests.java @@ -0,0 +1,117 @@ +package org.eclipse.cdt.build.core.scannerconfig.tests; + +import java.util.Map; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext; +import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set; +import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.testplugin.ManagedBuildTestHelper; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; + +public class CfgScannerConfigProfileManagerTests extends BaseTestCase { + IProject fProject; + + public static Test suite() { + TestSuite suite = new TestSuite(CfgScannerConfigProfileManagerTests.class.getName()); + suite.addTestSuite(CfgScannerConfigProfileManagerTests.class); + return suite; + } + + @Override + protected void setUp() throws Exception { + fProject = ManagedBuildTestHelper.createProject("CfgScannerConfigProfileManagerProj", + "cdt.managedbuild.target.gnu.exe"); + ManagedBuildTestHelper.addManagedBuildNature(fProject); + } + + @Override + protected void tearDown() throws Exception { + ManagedBuildTestHelper.removeProject(fProject.getName()); + } + + /** + * Basic testing of Config based ScannerConfigProfile management. + * + * This test runs through some of the funcationality used by the DiscoveryTab + * @throws CoreException + */ + public void testBasicCfgScannerConfigProfileChanges() throws CoreException { + ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(fProject); + ICConfigurationDescription[] cfgDescs = prjDesc.getConfigurations(); + assertTrue(cfgDescs.length > 0); + + IConfiguration cfg0 = ManagedBuildManager.getConfigurationForDescription(cfgDescs[0]); + ICfgScannerConfigBuilderInfo2Set scbis = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg0); + + // Test changing ICfgScannerConfigBuilderInfo2Set settings + boolean resCfgTypeDiscovery = scbis.isPerRcTypeDiscovery(); + scbis.setPerRcTypeDiscovery(!resCfgTypeDiscovery); + + // Test changing settings on one of the ScannerConfigBuilderInfos + Map infoMap = scbis.getInfoMap(); + CfgInfoContext cic = infoMap.entrySet().iterator().next().getKey(); + IScannerConfigBuilderInfo2 scbi = infoMap.entrySet().iterator().next().getValue(); + // Get all the settings and invert them + boolean autoDiscovery = scbi.isAutoDiscoveryEnabled(); + scbi.setAutoDiscoveryEnabled(!autoDiscovery); + boolean problemReport = scbi.isProblemReportingEnabled(); + scbi.setProblemReportingEnabled(!problemReport); + boolean buildOutputParser = scbi.isBuildOutputParserEnabled(); + scbi.setBuildOutputParserEnabled(!buildOutputParser); + boolean buildOutputFileAction = scbi.isBuildOutputFileActionEnabled(); + scbi.setBuildOutputFileActionEnabled(!buildOutputFileAction); + String buildOutputFilePath = scbi.getBuildOutputFilePath(); + scbi.setBuildOutputFilePath("dummyFile"); + // Persist the changes + scbis.applyInfo(cic, scbi); + + // Save the project description + CoreModel.getDefault().setProjectDescription(fProject, prjDesc); + fProject.close(null); + fProject.open(null); + + // Check that the changes have persisted + prjDesc = CoreModel.getDefault().getProjectDescription(fProject); + cfg0 = ManagedBuildManager.getConfigurationForDescription(prjDesc.getConfigurations()[0]); + scbis = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg0); + assertTrue(scbis.isPerRcTypeDiscovery() != resCfgTypeDiscovery); + scbi = scbis.getInfo(cic); + // Check that the changes have persisted + Assert.isTrue(autoDiscovery != scbi.isAutoDiscoveryEnabled()); + Assert.isTrue(problemReport != scbi.isProblemReportingEnabled()); + Assert.isTrue(buildOutputParser != scbi.isBuildOutputParserEnabled()); + Assert.isTrue(buildOutputFileAction != scbi.isBuildOutputFileActionEnabled()); + Assert.isTrue("dummyFile".equals(scbi.getBuildOutputFilePath())); + + // Test restore defaults + scbis.applyInfo(cic, null); + // Save the project description + CoreModel.getDefault().setProjectDescription(fProject, prjDesc); + fProject.close(null); + fProject.open(null); + + // Check settings are back to original + prjDesc = CoreModel.getDefault().getProjectDescription(fProject); + cfg0 = ManagedBuildManager.getConfigurationForDescription(prjDesc.getConfigurations()[0]); + scbis = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg0); + scbi = scbis.getInfo(cic); + Assert.isTrue(autoDiscovery == scbi.isAutoDiscoveryEnabled()); + Assert.isTrue(problemReport == scbi.isProblemReportingEnabled()); + Assert.isTrue(buildOutputParser == scbi.isBuildOutputParserEnabled()); + Assert.isTrue(buildOutputFileAction == scbi.isBuildOutputFileActionEnabled()); + Assert.isTrue(buildOutputFilePath.equals(buildOutputFilePath)); + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/projectmodel/tests/CProjectDescriptionSerializationTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/projectmodel/tests/CProjectDescriptionSerializationTests.java index 5a2031e61a0..9274031de4e 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/projectmodel/tests/CProjectDescriptionSerializationTests.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/projectmodel/tests/CProjectDescriptionSerializationTests.java @@ -15,10 +15,13 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.make.core.MakeCorePlugin; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.IProjectType; @@ -32,6 +35,8 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.QualifiedName; /** * Creates a project in a loop and checks that it is created with appropriate number * of build configurations @@ -139,4 +144,66 @@ public class CProjectDescriptionSerializationTests extends TestCase { } } } + + /** + * This test is intended to check persistentProperties after a project is created. + * @throws Exception + */ + public void testPersistentProperties() throws Exception { + CoreModel coreModel = CoreModel.getDefault(); + ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager(); + + String pluginProjectTypeId = "cdt.managedbuild.target.gnu.cygwin.exe"; + final String projectName = "testPersistentProperties"; + + { + // Create model project and accompanied descriptions + IProject project = BuildSystemTestHelper.createProject(projectName); + ICProjectDescription des = coreModel.createProjectDescription(project, false); + Assert.assertNotNull("createDescription returned null!", des); + + { + ManagedBuildInfo info = ManagedBuildManager.createBuildInfo(project); + IProjectType type = ManagedBuildManager.getProjectType(pluginProjectTypeId); + Assert.assertNotNull("project type not found", type); + + ManagedProject mProj = new ManagedProject(project, type); + info.setManagedProject(mProj); + + IConfiguration cfgs[] = type.getConfigurations(); + Assert.assertNotNull("configurations not found", cfgs); + Assert.assertTrue("no configurations found in the project type",cfgs.length>0); + + for (IConfiguration configuration : cfgs) { + String id = ManagedBuildManager.calculateChildId(configuration.getId(), null); + Configuration config = new Configuration(mProj, (Configuration)configuration, id, false, true, false); + CConfigurationData data = config.getConfigurationData(); + Assert.assertNotNull("data is null for created configuration", data); + ICConfigurationDescription cfgDes = des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); + } + Assert.assertEquals(2, des.getConfigurations().length); + } + + coreModel.setProjectDescription(project, des); + Assert.assertEquals(project, des.getProject()); + + Thread.sleep(1000); // let scanner discovery participate + try { + QualifiedName pdomName = new QualifiedName(CCorePlugin.PLUGIN_ID, "pdomName"); + QualifiedName activeCfg = new QualifiedName(CCorePlugin.PLUGIN_ID, "activeConfiguration"); + QualifiedName settingCfg = new QualifiedName(CCorePlugin.PLUGIN_ID, "settingConfiguration"); + QualifiedName discoveredScannerConfigFileName = new QualifiedName(MakeCorePlugin.PLUGIN_ID, "discoveredScannerConfigFileName"); + + assertTrue("pdomName", project.getPersistentProperties().containsKey(pdomName)); + assertTrue("activeCfg", project.getPersistentProperties().containsKey(activeCfg)); + assertTrue("discoveredScannerConfigFileName", project.getPersistentProperties().containsKey(discoveredScannerConfigFileName)); + assertTrue("settingCfg", project.getPersistentProperties().containsKey(settingCfg)); + } catch (CoreException e) { + Assert.fail(e.getMessage()); + } + + project.close(null); + } + } + } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java index 0d659cdd180..71f967e20df 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java @@ -59,8 +59,8 @@ import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICMultiConfigDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.settings.model.XmlStorageUtil; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; -import org.eclipse.cdt.core.settings.model.util.XmlStorageElement; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyManager; import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentBuildPathsChangeListener; @@ -2153,7 +2153,7 @@ public class ManagedBuildManager extends AbstractCExtension { Node node = nodes.item(0); // Create the internal representation of the project's MBS information - buildInfo = new ManagedBuildInfo(project, new XmlStorageElement((Element)node), true, fileVersion); + buildInfo = new ManagedBuildInfo(project, XmlStorageUtil.createCStorageTree((Element)node), true, fileVersion); if (fileVersion != null) { // buildInfo.setVersion(fileVersion); PluginVersionIdentifier version = new PluginVersionIdentifier(fileVersion); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedBuildInfo.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedBuildInfo.java index 26d1c71084d..022a0368adb 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedBuildInfo.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedBuildInfo.java @@ -29,7 +29,7 @@ import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.WriteAccessException; -import org.eclipse.cdt.core.settings.model.util.XmlStorageElement; +import org.eclipse.cdt.core.settings.model.XmlStorageUtil; import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IBuildObject; import org.eclipse.cdt.managedbuilder.core.IBuilder; @@ -743,7 +743,7 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo { if(managedProject != null){ Element projElement = doc.createElement(IManagedProject.MANAGED_PROJECT_ELEMENT_NAME); element.appendChild(projElement); - ((ManagedProject)managedProject).serialize(new XmlStorageElement(projElement), true); + ((ManagedProject)managedProject).serialize(XmlStorageUtil.createCStorageTree(projElement), true); } else{ Iterator iter = getTargets().listIterator(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedConfigStorageElement.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedConfigStorageElement.java index 2c84697e87d..b545934f4e2 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedConfigStorageElement.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedConfigStorageElement.java @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.internal.core; @@ -17,10 +18,11 @@ import java.util.List; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.WriteAccessException; import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +import org.eclipse.core.runtime.CoreException; public class ManagedConfigStorageElement implements ICStorageElement { private IManagedConfigElement fElement; - private List fChildList; + private List fChildList; private ManagedConfigStorageElement fParent; public ManagedConfigStorageElement(IManagedConfigElement el){ this(el, null); @@ -42,21 +44,37 @@ public class ManagedConfigStorageElement implements ICStorageElement { public String getAttribute(String name) { return fElement.getAttribute(name); } + + public boolean hasAttribute(String name) { + return fElement.getAttribute(name) != null; + } public ICStorageElement[] getChildren() { - List list = getChildList(true); - return (ManagedConfigStorageElement[])list.toArray(new ManagedConfigStorageElement[list.size()]); + List list = getChildList(true); + return list.toArray(new ManagedConfigStorageElement[list.size()]); } - private List getChildList(boolean create){ + private List getChildList(boolean create){ if(fChildList == null && create){ IManagedConfigElement children[] = fElement.getChildren(); - fChildList = new ArrayList(children.length); + fChildList = new ArrayList(children.length); fChildList.addAll(Arrays.asList(children)); } return fChildList; } + + public ICStorageElement[] getChildrenByName(String name) { + List children = new ArrayList(); + for (ICStorageElement child : getChildren()) + if (name.equals(child.getName())) + children.add(child); + return children.toArray(new ICStorageElement[children.size()]); + } + + public boolean hasChildren() { + return getChildList(true).isEmpty(); + } public String getName() { return fElement.getName(); @@ -94,4 +112,12 @@ public class ManagedConfigStorageElement implements ICStorageElement { public String[] getAttributeNames() { throw new UnsupportedOperationException(); } + + public ICStorageElement createCopy() throws UnsupportedOperationException, CoreException { + throw new UnsupportedOperationException(); + } + + public boolean equals(ICStorageElement other) { + throw new UnsupportedOperationException(); + } } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MapStorageElement.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MapStorageElement.java index 07838ab358b..5890feb8ef9 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MapStorageElement.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MapStorageElement.java @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.internal.core; @@ -18,36 +19,37 @@ import java.util.Map; import java.util.Map.Entry; import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.core.runtime.CoreException; public class MapStorageElement implements ICStorageElement { - private HashMap fMap; + private HashMap fMap; private String fName; private MapStorageElement fParent; private static final String CHILDREN_KEY = "?children?"; //$NON-NLS-1$ private static final String NAME_KEY = "?name?"; //$NON-NLS-1$ private static final String VALUE_KEY = "?value?"; //$NON-NLS-1$ - private List fChildren = new ArrayList(); + private List fChildren = new ArrayList(); private String fValue; public MapStorageElement(String name, MapStorageElement parent){ fName = name; fParent = parent; - fMap = new HashMap(); + fMap = new HashMap(); } - public MapStorageElement(Map map, MapStorageElement parent){ - fName = (String)map.get(getMapKey(NAME_KEY)); - fValue = (String)map.get(getMapKey(VALUE_KEY)); - fMap = new HashMap(map); + public MapStorageElement(Map map, MapStorageElement parent){ + fName = map.get(getMapKey(NAME_KEY)); + fValue = map.get(getMapKey(VALUE_KEY)); + fMap = new HashMap(map); fParent = parent; - String children = (String)map.get(getMapKey(CHILDREN_KEY)); + String children = map.get(getMapKey(CHILDREN_KEY)); if(children != null){ - List childrenStrList = decodeList(children); + List childrenStrList = decodeList(children); int size = childrenStrList.size(); if(size != 0){ for(int i = 0; i < size; i++){ - Map childMap = decodeMap((String)childrenStrList.get(i)); + Map childMap = decodeMap(childrenStrList.get(i)); MapStorageElement child = createChildElement(childMap); fChildren.add(child); } @@ -55,7 +57,7 @@ public class MapStorageElement implements ICStorageElement { } } - protected MapStorageElement createChildElement(Map childMap){ + protected MapStorageElement createChildElement(Map childMap){ return new MapStorageElement(childMap, this); } @@ -63,8 +65,8 @@ public class MapStorageElement implements ICStorageElement { return name; } - public Map toStringMap(){ - Map map = (Map)fMap.clone(); + public Map toStringMap(){ + Map map = (Map)fMap.clone(); if(fName != null) map.put(getMapKey(NAME_KEY), fName); else @@ -77,10 +79,10 @@ public class MapStorageElement implements ICStorageElement { int size = fChildren.size(); if(size != 0){ - List childrenStrList = new ArrayList(size); + List childrenStrList = new ArrayList(size); for(int i = 0; i < size; i++){ - MapStorageElement child = (MapStorageElement)fChildren.get(i); - Map childStrMap = child.toStringMap(); + MapStorageElement child = fChildren.get(i); + Map childStrMap = child.toStringMap(); String str = encodeMap(childStrMap); childrenStrList.add(str); } @@ -118,9 +120,25 @@ public class MapStorageElement implements ICStorageElement { return (String)o; return null; } + + public boolean hasAttribute(String name) { + return fMap.containsKey(getMapKey(name)); + } public ICStorageElement[] getChildren() { - return (MapStorageElement[])fChildren.toArray(new MapStorageElement[fChildren.size()]); + return fChildren.toArray(new MapStorageElement[fChildren.size()]); + } + + public ICStorageElement[] getChildrenByName(String name) { + List children = new ArrayList(); + for (ICStorageElement child : fChildren) + if (name.equals(child.getName())) + children.add(child); + return new ICStorageElement[children.size()]; + } + + public boolean hasChildren() { + return !fChildren.isEmpty(); } public String getName() { @@ -150,13 +168,13 @@ public class MapStorageElement implements ICStorageElement { fMap.put(getMapKey(name), value); } - public static Map decodeMap(String value) { - List list = decodeList(value); - Map map = new HashMap(); + public static Map decodeMap(String value) { + List list = decodeList(value); + Map map = new HashMap(); char escapeChar = '\\'; for(int i = 0; i < list.size(); i++){ - StringBuffer line = new StringBuffer((String)list.get(i)); + StringBuffer line = new StringBuffer(list.get(i)); int lndx = 0; while (lndx < line.length()) { if (line.charAt(lndx) == '=') { @@ -176,8 +194,8 @@ public class MapStorageElement implements ICStorageElement { } - public static List decodeList(String value) { - List list = new ArrayList(); + public static List decodeList(String value) { + List list = new ArrayList(); if (value != null) { StringBuffer envStr = new StringBuffer(value); String escapeChars = "|\\"; //$NON-NLS-1$ @@ -222,8 +240,8 @@ public class MapStorageElement implements ICStorageElement { return list; } - public static String encodeMap(Map values) { - List list = new ArrayList(); + public static String encodeMap(Map values) { + List list = new ArrayList(); Iterator entries = values.entrySet().iterator(); StringBuffer str = new StringBuffer(); while (entries.hasNext()) { @@ -237,11 +255,11 @@ public class MapStorageElement implements ICStorageElement { return encodeList(list); } - public static String encodeList(List values) { + public static String encodeList(List values) { StringBuffer str = new StringBuffer(); - Iterator entries = values.iterator(); + Iterator entries = values.iterator(); while (entries.hasNext()) { - String entry = (String)entries.next(); + String entry = entries.next(); str.append(escapeChars(entry, "|\\", '\\')); //$NON-NLS-1$ // str.append("="); //$NON-NLS-1$ // str.append(escapeChars((String)entry.getValue(), "|\\", '\\')); //$NON-NLS-1$ @@ -276,7 +294,7 @@ public class MapStorageElement implements ICStorageElement { } public String[] getAttributeNames() { - List list = new ArrayList(fMap.size()); + List list = new ArrayList(fMap.size()); for(Iterator iter = fMap.entrySet().iterator(); iter.hasNext();){ Map.Entry entry = (Map.Entry)iter.next(); String key = (String)entry.getKey(); @@ -285,6 +303,14 @@ public class MapStorageElement implements ICStorageElement { } } - return (String[])list.toArray(new String[list.size()]); + return list.toArray(new String[list.size()]); + } + + public ICStorageElement createCopy() throws UnsupportedOperationException, CoreException { + throw new UnsupportedOperationException(); + } + + public boolean equals(ICStorageElement other) { + throw new UnsupportedOperationException(); } } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/dataprovider/ConfigurationDataProvider.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/dataprovider/ConfigurationDataProvider.java index ebc780a8afd..7b44b0a49a1 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/dataprovider/ConfigurationDataProvider.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/dataprovider/ConfigurationDataProvider.java @@ -108,6 +108,8 @@ public class ConfigurationDataProvider extends CConfigurationDataProvider implem ICStorageElement cfgElemen = rootElement.createChild(IConfiguration.CONFIGURATION_ELEMENT_NAME); Configuration cfg = (Configuration)appliedCfg.getConfiguration(); Builder b = (Builder)cfg.getEditableBuilder(); + // Need to ensure that build macro supplier can get the description for this configuration during the write... + cfg.setConfigurationDescription(des); if(b != null && b.isManagedBuildOn() && b.getBuildPathAttribute(false) == null){ String bPath = b.getDefaultBuildPath(); b.setBuildPathAttribute(bPath); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/scannerconfig/IManagedScannerInfoCollector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/scannerconfig/IManagedScannerInfoCollector.java index d6dade64967..df318d51876 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/scannerconfig/IManagedScannerInfoCollector.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/scannerconfig/IManagedScannerInfoCollector.java @@ -17,7 +17,7 @@ import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector; import org.eclipse.core.resources.IProject; /** - * Interface that a colelctor of compiler information must implement. + * Interface that a collector of compiler information must implement. * @since 2.0 */ public interface IManagedScannerInfoCollector extends IScannerInfoCollector { @@ -31,7 +31,7 @@ public interface IManagedScannerInfoCollector extends IScannerInfoCollector { * * @return a Map of defined symbols and values */ - public Map getDefinedSymbols(); + public Map getDefinedSymbols(); /** diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/newmake/core/MakeScannerProvider.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/newmake/core/MakeScannerProvider.java index bd37f6d5579..57d5e518449 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/newmake/core/MakeScannerProvider.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/newmake/core/MakeScannerProvider.java @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.newmake.core; @@ -26,6 +27,7 @@ import org.eclipse.cdt.core.model.IMacroEntry; import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.resources.ScannerProvider; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -35,8 +37,6 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; -import org.w3c.dom.Element; -import org.w3c.dom.Node; /** * @deprecated @author DInglis @@ -114,18 +114,17 @@ public class MakeScannerProvider extends ScannerProvider { */ private MakeScannerInfo loadScannerInfo(IProject project) throws CoreException { ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project); - Node child = descriptor.getProjectData(CDESCRIPTOR_ID).getFirstChild(); + ICStorageElement root = descriptor.getProjectStorageElement(CDESCRIPTOR_ID); ArrayList includes = new ArrayList(); ArrayList symbols = new ArrayList(); - while (child != null) { - if (child.getNodeName().equals(INCLUDE_PATH)) { + for (ICStorageElement child : root.getChildren()) { + if (child.getName().equals(INCLUDE_PATH)) { // Add the path to the property list - includes.add( ((Element)child).getAttribute(PATH)); - } else if (child.getNodeName().equals(DEFINED_SYMBOL)) { + includes.add(child.getAttribute(PATH)); + } else if (child.getName().equals(DEFINED_SYMBOL)) { // Add the symbol to the symbol list - symbols.add( ((Element)child).getAttribute(SYMBOL)); + symbols.add(child.getAttribute(SYMBOL)); } - child = child.getNextSibling(); } MakeScannerInfo info = new MakeScannerInfo(project); info.setIncludePaths((String[])includes.toArray(new String[includes.size()])); @@ -194,15 +193,11 @@ public class MakeScannerProvider extends ScannerProvider { ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project); - Element rootElement = descriptor.getProjectData(CDESCRIPTOR_ID); + ICStorageElement rootElement = descriptor.getProjectStorageElement(CDESCRIPTOR_ID); // Clear out all current children // Note: Probably would be a better idea to merge in the data - Node child = rootElement.getFirstChild(); - while (child != null) { - rootElement.removeChild(child); - child = rootElement.getFirstChild(); - } + rootElement.clear(); descriptor.saveProjectData(); migrateToCPathEntries(scannerInfo); diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorTests.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorTests.java index 126e0da9936..91b0987643c 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorTests.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorTests.java @@ -8,14 +8,20 @@ * Contributors: * QNX Software Systems Ltd - initial API and implementation * Anton Leherbauer (Wind River Systems) + * James Blackburn (Broadcom Corp.) ***********************************************************************/ package org.eclipse.cdt.core.cdescriptor.tests; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Method; + import junit.extensions.TestSetup; import junit.framework.Assert; import junit.framework.Test; -import junit.framework.TestCase; import junit.framework.TestSuite; import org.eclipse.cdt.core.CCorePlugin; @@ -26,8 +32,12 @@ import org.eclipse.cdt.core.ICDescriptorListener; import org.eclipse.cdt.core.ICDescriptorOperation; import org.eclipse.cdt.core.ICExtensionReference; import org.eclipse.cdt.core.ICOwnerInfo; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.testplugin.CTestPlugin; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.internal.core.pdom.PDOMManager; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; @@ -35,9 +45,7 @@ import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; +import org.eclipse.core.runtime.NullProgressMonitor; /** * @author David @@ -45,12 +53,12 @@ import org.w3c.dom.NodeList; * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */ -public class CDescriptorTests extends TestCase { +public class CDescriptorTests extends BaseTestCase { static String projectId = CTestPlugin.PLUGIN_ID + ".TestProject"; static IProject fProject; static CDescriptorListener listener = new CDescriptorListener(); - static CDescriptorEvent fLastEvent; + static volatile CDescriptorEvent fLastEvent; /** * Constructor for CDescriptorTest. @@ -64,18 +72,11 @@ public class CDescriptorTests extends TestCase { public static Test suite() { TestSuite suite = new TestSuite(CDescriptorTests.class.getName()); - suite.addTest(new CDescriptorTests("testDescriptorCreation")); - suite.addTest(new CDescriptorTests("testDescriptorOwner")); - suite.addTest(new CDescriptorTests("testExtensionCreation")); - suite.addTest(new CDescriptorTests("testExtensionGet")); - suite.addTest(new CDescriptorTests("testExtensionData")); - suite.addTest(new CDescriptorTests("testExtensionRemove")); - suite.addTest(new CDescriptorTests("testProjectDataCreate")); - suite.addTest(new CDescriptorTests("testProjectDataDelete")); - suite.addTest(new CDescriptorTests("testConcurrentDescriptorCreation")); - suite.addTest(new CDescriptorTests("testConcurrentDescriptorCreation2")); - suite.addTest(new CDescriptorTests("testDeadlockDuringProjectCreation")); - + // Add all the tests in this class + for (Method m : CDescriptorTests.class.getMethods()) + if (m.getName().startsWith("test")) + suite.addTest(new CDescriptorTests(m.getName())); + TestSetup wrapper = new TestSetup(suite) { @Override @@ -91,7 +92,16 @@ public class CDescriptorTests extends TestCase { }; return wrapper; } + + @Override + protected void setUp() throws Exception { + fProject.open(new NullProgressMonitor()); + } + @Override + protected void tearDown() throws Exception { + } + private static void addNatureToProject(IProject proj, String natureId, IProgressMonitor monitor) throws CoreException { IProjectDescription description = proj.getDescription(); String[] prevNatures = description.getNatureIds(); @@ -155,44 +165,59 @@ public class CDescriptorTests extends TestCase { Assert.assertEquals("*", desc.getPlatform()); } + public void testDescriptorOwner() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICOwnerInfo owner = desc.getProjectOwner(); + Assert.assertEquals(projectId, owner.getID()); + Assert.assertEquals("*", owner.getPlatform()); + Assert.assertEquals("C/C++ Test Project", owner.getName()); + } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185930 public void testConcurrentDescriptorCreation() throws Exception { - fProject.close(null); - fProject.open(null); - Thread t= new Thread() { - @Override - public void run() { - try { - CCorePlugin.getDefault().getCProjectDescription(fProject, true); - } catch (CoreException exc) { + for (int i = 0; i < 100 ; i++) { + fProject.close(null); + fProject.open(null); + Thread t= new Thread() { + public void run() { + try { + CCorePlugin.getDefault().getCProjectDescription(fProject, true); + } catch (CoreException exc) { + fail(); + } } - } - }; - t.start(); - ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - t.join(); - - Element data = desc.getProjectData("testElement0"); - data.appendChild(data.getOwnerDocument().createElement("test")); - desc.saveProjectData(); - fLastEvent = null; + }; + t.start(); + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + t.join(); + + ICStorageElement data = desc.getProjectStorageElement("testElement0"); + data.createChild("test"); + desc.saveProjectData(); + fLastEvent = null; + } } + /* + * This tests concurrent descriptor modification inside of a ICDescriptor operation run + * with + * CConfigBasedDescriptorManager.runDescriptorOperation(IProject project, ICDescriptorOperation op, IProgressMonitor monitor) + */ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185930 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=193503 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=196118 - public void testConcurrentDescriptorCreation2() throws Exception { + public void testConcurrentDescriptorModification() throws Exception { int lastLength = 0; - for (int i=0; i<200; ++i) { + for (int i=0; i<100; ++i) { final int indexi = i; PDOMManager pdomMgr= (PDOMManager)CCorePlugin.getIndexManager(); pdomMgr.shutdown(); fProject.close(null); fProject.open(null); pdomMgr.startup().schedule(); - ICDescriptor desc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); + final ICDescriptor fdesc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); if (lastLength == 0) - lastLength = countChildElements(desc.getProjectData("testElement")); + lastLength = fdesc.getProjectStorageElement("testElement").getChildren().length; final Throwable[] exception= new Throwable[10]; Thread[] threads= new Thread[10]; for (int j = 0; j < 10; j++) { @@ -203,22 +228,15 @@ public class CDescriptorTests extends TestCase { try { ICDescriptorOperation operation= new ICDescriptorOperation() { public void execute(ICDescriptor descriptor, IProgressMonitor monitor) throws CoreException { - assertFalse(descriptor.getConfigurationDescription().isReadOnly()); - Element data = descriptor.getProjectData("testElement"); +// assertFalse(descriptor.getConfigurationDescription().isReadOnly()); + ICStorageElement data = fdesc.getProjectStorageElement("testElement"); String test = "test"+(indexi*10 + indexj); - data.appendChild(data.getOwnerDocument().createElement(test)); - assertFalse(descriptor.getConfigurationDescription().isReadOnly()); - // BUG196118 the model cached in memory doesn't reflect the contents of .cproject - // - // descriptor.saveProjectData() doesn't actually save despite what the API says - // see CConfigBasedDescriptor.fApplyOnChange -// ((CConfigBasedDescriptor)descriptor).apply(false); + data.createChild(test); +// assertFalse(descriptor.getConfigurationDescription().isReadOnly()); + descriptor.saveProjectData(); // System.out.println("Saved " + test); }}; CCorePlugin.getDefault().getCDescriptorManager().runDescriptorOperation(fProject, operation, null); - ICDescriptor descriptor = CCorePlugin.getDefault().getCDescriptorManager().getDescriptor(fProject); - // perform apply outside descriptor operation to avoid deadlock - http://bugs.eclipse.org/241288 - descriptor.saveProjectData(); } catch (Throwable exc) { exception[indexj]= exc; exc.printStackTrace(); @@ -234,8 +252,8 @@ public class CDescriptorTests extends TestCase { } assertNull("Exception occurred: "+exception[j], exception[j]); } - desc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); - int lengthAfter = countChildElements(desc.getProjectData("testElement")); + ICDescriptor desc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); + int lengthAfter = desc.getProjectStorageElement("testElement").getChildren().length; lastLength += threads.length; // Update last lengths to what we expect assertEquals("Iteration count: " + i, lastLength, lengthAfter); @@ -243,43 +261,92 @@ public class CDescriptorTests extends TestCase { } } - /** - * Count the number of Node.ELEMENT_NODE elements which are a - * direct descendent of the parent Element. - * Other nodes (e.g. Text) are ignored - * @param parent - * @return + /* + * This test should pass as two threads, operating on the + * different storage elements (outside of an operation) should be safe */ - private int countChildElements(Element parent) { - int numElements = 0; - NodeList childNodes = parent.getChildNodes(); - for (int k = 0 ; k < childNodes.getLength() ; k++) - if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) - numElements ++; - return numElements; - } - - public void testDeadlockDuringProjectCreation() throws Exception { - for (int i=0; i < 10; ++i) { - oneTimeTearDown(); - oneTimeSetUp(); + public void testConcurrentDifferentStorageElementModification() throws Exception { + for (int i=0; i < 100; ++i) { Thread t= new Thread() { - @Override public void run() { try { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element data = desc.getProjectData("testElement0"); - data.appendChild(data.getOwnerDocument().createElement("test")); + ICStorageElement data = desc.getProjectStorageElement("testElement4"); + data.createChild("test"); desc.saveProjectData(); } catch (CoreException exc) { + fail(exc.getMessage()); } } }; t.start(); ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element data = desc.getProjectData("testElement0"); - data.appendChild(data.getOwnerDocument().createElement("test")); + ICStorageElement data = desc.getProjectStorageElement("testElement5"); + data.createChild("test"); + desc.saveProjectData(); + t.join(); + + fLastEvent = null; + } + Assert.assertEquals(100, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement4").getChildren().length); + Assert.assertEquals(100, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement5").getChildren().length); + } + + /* + * Test that (non-structural) changes to the storage element tree + * work as expected. + */ + public void testConcurrentSameStorageElementModification() throws Exception { + for (int i=0; i < 100; ++i) { + Thread t= new Thread() { + public void run() { + try { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("testElement6"); + data.createChild("test"); + desc.saveProjectData(); + } catch (CoreException exc) { + fail(exc.getMessage()); + } + } + }; + t.start(); + + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("testElement6"); + data.createChild("test"); + desc.saveProjectData(); + t.join(); + + fLastEvent = null; + } + Assert.assertEquals(200, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement6").getChildren().length); + } + + /* + * Tests deadlock when accessing c project description concurrently from two threads + */ + public void testDeadlockDuringProjectCreation() throws Exception { + for (int i=0; i < 10; ++i) { + oneTimeTearDown(); + oneTimeSetUp(); + Thread t= new Thread() { + public void run() { + try { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("testElement0"); + data.createChild("test"); + desc.saveProjectData(); + } catch (Exception exc) { + } + } + }; + t.start(); + + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("testElement0"); + data.createChild("test"); desc.saveProjectData(); t.join(); @@ -287,14 +354,6 @@ public class CDescriptorTests extends TestCase { } } - public void testDescriptorOwner() throws Exception { - ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - ICOwnerInfo owner = desc.getProjectOwner(); - Assert.assertEquals(projectId, owner.getID()); - Assert.assertEquals("*", owner.getPlatform()); - Assert.assertEquals("C/C++ Test Project", owner.getName()); - } - public void testDescriptorConversion() { } @@ -352,8 +411,8 @@ public class CDescriptorTests extends TestCase { public void testProjectDataCreate() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element data = desc.getProjectData("testElement"); - data.appendChild(data.getOwnerDocument().createElement("test")); + ICStorageElement data = desc.getProjectStorageElement("testElement"); + data.createChild("test"); desc.saveProjectData(); Assert.assertNotNull(fLastEvent); @@ -365,10 +424,10 @@ public class CDescriptorTests extends TestCase { public void testProjectDataDelete() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element data = desc.getProjectData("testElement"); - NodeList list = data.getElementsByTagName("test"); - Assert.assertEquals(1, list.getLength()); - data.removeChild(data.getFirstChild()); + ICStorageElement data = desc.getProjectStorageElement("testElement"); + ICStorageElement[] list = data.getChildrenByName("test"); + Assert.assertEquals(1, list.length); + data.removeChild(list[0]); desc.saveProjectData(); Assert.assertNotNull(fLastEvent); @@ -378,4 +437,103 @@ public class CDescriptorTests extends TestCase { fLastEvent = null; } + public void testCProjectDescriptionDescriptorInteraction() throws Exception { + for (int i = 1; i < 100 ; i++) { + // Create a descriptor with some test data + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("descDescInteraction"); + data.createChild("dataItem1"); + + // Get the CProjectDescription + ICProjectDescription projDesc = CCorePlugin.getDefault().getProjectDescription(fProject); + data = desc.getProjectStorageElement("descDescInteraction"); + data.createChild("dataItem2"); + data = desc.getProjectStorageElement("descDescInteraction2"); + data.createChild("dataItem3"); + + // save the descriptor + desc.saveProjectData(); + // save the project description + CCorePlugin.getDefault().setProjectDescription(fProject, projDesc); + + fProject.close(null); + assertTrue(CCorePlugin.getDefault().getCProjectDescription(fProject, false) == null); + fProject.open(null); + + // Check that the descriptor added data is still there + desc = CCorePlugin.getDefault().getCProjectDescription(fProject, false); + data = desc.getProjectStorageElement("descDescInteraction"); + assertEquals(2 * i, data.getChildren().length); + data = desc.getProjectStorageElement("descDescInteraction2"); + assertEquals(1 * i, data.getChildren().length); + } + } + + public void testAccumulatingBlankLinesInProjectData() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICStorageElement data = desc.getProjectStorageElement("testElement"); + data.createChild("test"); + desc.saveProjectData(); + + fProject.close(null); + fProject.open(null); + + String dotCProject1 = readDotCProjectFile(fProject); + long mtime1 = fProject.getFile(".cproject").getLocalTimeStamp(); + + desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + data = desc.getProjectStorageElement("testElement"); + for (ICStorageElement child : data.getChildren()) { + data.removeChild(child); + } + data.createChild("test"); + desc.saveProjectData(); + + String dotCProject2 = readDotCProjectFile(fProject); + long mtime2 = fProject.getFile(".cproject").getLocalTimeStamp(); + assertEquals("Difference in .cproject file", dotCProject1, dotCProject2); + assertTrue(".cproject file has been written", mtime1 == mtime2); + + // do it a second time - just to be sure + fProject.close(null); + fProject.open(null); + + desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + data = desc.getProjectStorageElement("testElement"); + for (ICStorageElement child : data.getChildren()) { + data.removeChild(child); + } + data.createChild("test"); + desc.saveProjectData(); + + String dotCProject3 = readDotCProjectFile(fProject); + long mtime3 = fProject.getFile(".cproject").getLocalTimeStamp(); + assertEquals("Difference in .cproject file", dotCProject2, dotCProject3); + assertTrue(".cproject file has been written", mtime2 == mtime3); + } + + /** + * Read .cproject file. + * + * @param project + * @return content of .cproject file + * @throws CoreException + * @throws IOException + */ + private static String readDotCProjectFile(IProject project) throws CoreException, IOException { + IFile cProjectFile = project.getFile(".cproject"); + InputStream in = cProjectFile.getContents(); + try { + Reader reader = new InputStreamReader(in, "UTF-8"); + StringBuilder sb = new StringBuilder(); + char[] b = new char[4096]; + int n; + while ((n = reader.read(b)) > 0) { + sb.append(b, 0, n); + } + return sb.toString(); + } finally { + in.close(); + } + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java index 12e0bff9559..e7273319696 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java @@ -29,7 +29,7 @@ public class AllCProjectDescriptionTests { suite.addTest(ProjectCreationStateTests.suite()); suite.addTest(BackwardCompatibilityTests.suite()); suite.addTest(CProjectDescriptionBasicTests.suite()); + suite.addTest(CProjectDescriptionStorageTests.suite()); return suite; - } } diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/BackwardCompatibilityTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/BackwardCompatibilityTests.java index 15ccc816587..0324310dd64 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/BackwardCompatibilityTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/BackwardCompatibilityTests.java @@ -219,8 +219,7 @@ public class BackwardCompatibilityTests extends BaseTestCase { private void doTestRm(IProject proj) throws CoreException{ final String DATA_ID = "testICDescriptorGetProjectData"; ICDescriptor dr = CCorePlugin.getDefault().getCProjectDescription(proj, false); - Element dataEl = dr.getProjectData(DATA_ID); - dataEl.getParentNode().removeChild(dataEl); + dr.removeProjectStorageElement(DATA_ID); dr.saveProjectData(); } diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionBasicTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionBasicTests.java index 3b972cc29d4..7a23ab39a12 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionBasicTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionBasicTests.java @@ -10,8 +10,11 @@ *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import java.util.Map; + import junit.framework.TestSuite; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CProjectNature; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.model.CoreModel; @@ -189,6 +192,7 @@ public class CProjectDescriptionBasicTests extends BaseTestCase{ assertTrue(failed); } + public void testBug242955() throws Exception { CoreModel coreModel = CoreModel.getDefault(); diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionStorageTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionStorageTests.java new file mode 100644 index 00000000000..4b1ccc43051 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionStorageTests.java @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.settings.model; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IPDOMManager; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.testplugin.CProjectHelper; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * Testsuite for the project description storage. This + * currently tests some of the features of the built-in + * XmlProjectDescriptionStorage(2) + */ +public class CProjectDescriptionStorageTests extends BaseTestCase { + + /** CProject on which these tests are based */ + ICProject cProj; + + public static TestSuite suite() { + return suite(CProjectDescriptionStorageTests.class, "_"); + } + + // resource change listener that will listen for file changes interesting to the tests + OurResourceChangeListener resListener; + + @Override + protected void setUp() throws Exception { + cProj = CProjectHelper.createNewStileCProject("CProjDescStorage", IPDOMManager.ID_FAST_INDEXER); + resListener = new OurResourceChangeListener(); + ResourcesPlugin.getWorkspace().addResourceChangeListener(resListener); + } + + @Override + protected void tearDown() throws Exception { + // Remover our resource change listener + ResourcesPlugin.getWorkspace().removeResourceChangeListener(resListener); + // Make the project files writable so they can be deleted... + cProj.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + cProj.getProject().getFile(".cproject").setReadOnly(false); + if (cProj.getProject().getFolder(".csettings").exists()) { + cProj.getProject().getFolder(".csettings").setReadOnly(false); + for (IResource child : cProj.getProject().getFolder(".csettings").members()) + child.setReadOnly(false); + } + // Delete the project + CProjectHelper.delete(cProj); + } + + /** + * Tests that external modifications to the CProjectDescription file are picked up + * @throws Exception + */ + public void testExternalCProjDescModification() throws Exception { + // Create auto-refresh Thread + Job refreshJob = new Job("Auto-Refresh") { + @Override + protected IStatus run(IProgressMonitor monitor) { + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + try { + ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null); + } catch (CoreException e) { + fail("Error during refresh: " + e.getMessage()); + } + schedule(500); + return Status.OK_STATUS; + } + }; + refreshJob.schedule(); + + // Backup the CProjectFile + final String initial = "initial"; + final String testingStorage = "testingStorage"; + final String testChildInStorage = "testChildInStorage"; + + // Backup the original storage file + backUpCProjectFile(initial); + + IProject project = cProj.getProject(); + ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription(project, true); + projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, true).createChild(testChildInStorage); + CoreModel.getDefault().setProjectDescription(project, projDesc); + // backup this project_desc + backUpCProjectFile(testingStorage); + + // Close and open project + project.close(null); + project.open(null); + + // verify changes are in read-only description + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertNotNull(projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false)); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + + // Restore from backup + resListener.reset(); + resListener.addFileToWatch(cProj.getProject().getFile(".cproject").getFullPath()); + restoreCProjectFile(initial); + resListener.waitForChange(); + + // Fetch what should be the initial project description + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertNull(projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false)); + + // Test XmlProjectDescriptionStorage2: + + // Test that updating the contents of a storage module leads to a reload of the project description + // (In XmlProjectDescriptionStorage2 configuration storage modules are stored in different files...) + restoreCProjectFile(testingStorage); + project.close(null); + project.open(null); + + // create testChildInStorage + projDesc = CoreModel.getDefault().getProjectDescription(project, true); + ICStorageElement[] children = projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false).getChildrenByName(testChildInStorage); + assertTrue(children.length == 1); + projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false).removeChild(children[0]); + CoreModel.getDefault().setProjectDescription(project, projDesc); + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertTrue(projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false).getChildrenByName(testChildInStorage).length == 0); + + project.refreshLocal(IResource.DEPTH_INFINITE, null); + // Restore from backup + resListener.reset(); + resListener.addFileToWatch(cProj.getProject().getFolder(".csettings").getFullPath()); + restoreCProjectFile(testingStorage); + resListener.waitForChange(); + + // Check that the project description no longer contains the testChildInStorage + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertTrue(projDesc.getDefaultSettingConfiguration().getStorage(testingStorage, false).getChildrenByName(testChildInStorage).length == 1); + + refreshJob.cancel(); + } + + /** + * Tests that a read-only project description file is picked up + * @throws Exception + */ + public void testReadOnlyProjectDescription() throws Exception { + makeDescriptionReadOnly(); + IProject project = cProj.getProject(); + ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription(project, true); + projDesc.getDefaultSettingConfiguration().getStorage("Temp_testing_storage", true); + CoreModel.getDefault().setProjectDescription(project, projDesc); + + project.close(null); + project.open(null); + + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertNotNull(projDesc.getDefaultSettingConfiguration().getStorage("Temp_testing_storage", false)); + projDesc = CoreModel.getDefault().getProjectDescription(project, true); + makeDescriptionReadOnly(); + projDesc.getDefaultSettingConfiguration().removeStorage("Temp_testing_storage"); + CoreModel.getDefault().setProjectDescription(project, projDesc); + + project.close(null); + project.open(null); + + projDesc = CoreModel.getDefault().getProjectDescription(project, false); + assertNull(projDesc.getDefaultSettingConfiguration().getStorage("Temp_testing_storage", false)); + } + + /* + * + * Helper methods for external modifications + * + */ + + /** + * makes the project description (as stored by the XmlProjectDescriptionStorage & + * XmlProjectDescriptionStorage2) read-only. Does this using java.io.File deliberately. + */ + private void makeDescriptionReadOnly() throws Exception { + File cproj = cProj.getProject().getFile(".cproject").getLocation().toFile(); + if (!cproj.exists()) + throw new FileNotFoundException(); + cproj.setReadOnly(); + // XmlProjectDescription2 stores settings in a .csettings directory, look for it + File csettDir = cProj.getProject().getFile(".csettings").getLocation().toFile(); + if (csettDir.exists()) { + for (File child : csettDir.listFiles()) + child.setReadOnly(); + csettDir.setReadOnly(); + } + } + + /** + * Restore the file from the backup. Only does so if the contents of the file + * have changed (to prevent updating the modification stamp on the file...) + * @param uniqueKey + */ + private void restoreCProjectFile(String uniqueKey) { + File cproj = cProj.getProject().getFile(".cproject").getLocation().toFile(); + File cprojback = cProj.getProject().getFile(".cproject_" + uniqueKey).getLocation().toFile(); + if (diff(cprojback, cproj)) + copyFile(cprojback, cproj); + File csettings = cProj.getProject().getFile(".csettings").getLocation().toFile(); + File csettingsback = cProj.getProject().getFile(".csettings_" + uniqueKey).getLocation().toFile(); + if (csettingsback.exists()) { + for (File f : csettingsback.listFiles()) { + File orig = new File(csettings, f.getName()); + if (diff(f, orig)) + copyFile(f, orig); + } + } + } + + private void backUpCProjectFile(String uniqueKey) { + File cproj = cProj.getProject().getFile(".cproject").getLocation().toFile(); + File cprojback = cProj.getProject().getFile(".cproject_" + uniqueKey).getLocation().toFile(); + copyFile(cproj, cprojback); + // backup .csettings as well + File csettings = cProj.getProject().getFile(".csettings").getLocation().toFile(); + if (csettings.exists() && csettings.isDirectory()) { + File csettingsback = cProj.getProject().getFile(".csettings_" + uniqueKey).getLocation().toFile(); + if (!csettingsback.exists()) + csettingsback.mkdir(); + for (File f : csettings.listFiles()) + copyFile(f, new File(csettingsback, f.getName())); + } + } + + /** + * Return boolean indicating whether two files are different + * @param src1 + * @param src2 + * @return + */ + private boolean diff(File src1, File src2) { + if (!src1.exists() || !src2.exists()) + return true; + FileInputStream in1 = null; + FileInputStream in2 = null; + try { + in1 = new FileInputStream(src1); + in2 = new FileInputStream(src2); + while (true) { + int byteRead1 = in1.read(); + int byteRead2 = in2.read(); + if (byteRead1 == -1 && byteRead2 == -1) + return false; + if (byteRead1 != byteRead2) + return true; + } + } catch (Exception e) { + fail("Exception diffingFiles: " + src1.getAbsolutePath() + " ; " + src2.getAbsolutePath()); + return true; + } finally { + if (in1 != null) + try {in1.close();} catch (Exception e) {/*Don't care*/} + if (in2 != null) + try {in2.close();} catch (Exception e) {/*Don't care*/} + } + } + + private void copyFile(File src, File dst) { + long initModificationTime = dst.lastModified(); + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(src); + out = new FileOutputStream(dst); + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) + out.write(buffer, 0, bytesRead); + } catch (Exception e) { + fail("Exception copyingFile: " + src.getAbsolutePath() + " -> " + dst.getAbsolutePath()); + } finally { + if (in != null) + try {in.close();} catch (Exception e) {/*Don't care*/} + if (out != null) + try {out.close();} catch (Exception e) {/*Don't care*/} + } + + while (dst.lastModified() - initModificationTime == 0) { + // Unix stat doesn't return granularity < 1000ms :( + // If we don't sleep here, and the unit test goes too quickly, we're scuppered. + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Don't care + } + dst.setLastModified(System.currentTimeMillis()); + } + } + + /** + * Our resource change listener which notified us when a file has been detected as changed + * Users add files to the files to watch. Reset the listener and block waiting for the change to + * be noticed. + */ + private static class OurResourceChangeListener implements IResourceChangeListener { + boolean changeDetected; + private Set filesToWatch = new HashSet(); + public synchronized void resourceChanged(IResourceChangeEvent event) { + IResourceDelta delta = event.getDelta(); + if (delta == null) + return; + for (IPath f : filesToWatch) + if (delta.findMember(f) != null) { + changeDetected = true; + notifyAll(); + break; + } + } + public synchronized void addFileToWatch(IPath file) { + filesToWatch.add(file); + } + public synchronized void reset() { + changeDetected = false; + } + public synchronized void waitForChange() { + try { + if (!changeDetected) + wait(20000); + if (!changeDetected) + CCorePlugin.log("No Change detected in 20s!"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java index 9f49a666e8e..751861e0a52 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java @@ -652,7 +652,7 @@ class MockConfig implements ICConfigurationDescription { CConfigurationData data) throws WriteAccessException {} public void setDescription(String des) throws WriteAccessException {} public void setName(String name) throws WriteAccessException {} - public void setReferenceInfo(Map refs) throws WriteAccessException {} + public void setReferenceInfo(Map refs) throws WriteAccessException {} public void setSessionProperty(QualifiedName name, Object value) {} public void setSourceEntries(ICSourceEntry[] entries) throws CoreException, WriteAccessException {} @@ -663,8 +663,10 @@ class MockConfig implements ICConfigurationDescription { public int getType() {return 0;} public boolean isReadOnly() {return false;} public boolean isValid() {return false;} - public ICStorageElement getStorage(String id, boolean create) - throws CoreException { + public ICStorageElement getStorage(String id, boolean create) throws CoreException { + return null; + } + public ICStorageElement importStorage(String id, ICStorageElement storage) { return null; } @@ -690,6 +692,8 @@ class MockConfig implements ICConfigurationDescription { public CConfigurationStatus getConfigurationStatus() { return CConfigurationStatus.CFG_STATUS_OK; } + + public void setReadOnly(boolean readOnly, boolean keepModify) {} } /* diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionEvent.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionEvent.java index 5725ffe8d7d..52eab71257f 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionEvent.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/CProjectDescriptionEvent.java @@ -14,6 +14,14 @@ import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionDelta; import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; import org.eclipse.core.resources.IProject; +/** + * Events fired for the project delats. + * + * FIXME JBB: Should work out the difference between DATA_APPLIED AND APPLIED events + * current DATA_APPLIED occurs first and fNewDescription is modified. Need to clearly define + * the project description state transitions + */ + public final class CProjectDescriptionEvent { public static final int LOADED = 1; public static final int ABOUT_TO_APPLY = 1 << 1; @@ -23,7 +31,9 @@ public final class CProjectDescriptionEvent { public static final int ALL = LOADED | ABOUT_TO_APPLY | APPLIED | COPY_CREATED | DATA_APPLIED; private int fType; + /** A *writable* new description */ private ICProjectDescription fNewDescription; + /** The previous description should be read-only */ private ICProjectDescription fOldDescription; private ICProjectDescription fAppliedDescription; private ICDescriptionDelta fProjDelta; @@ -138,6 +148,10 @@ public final class CProjectDescriptionEvent { return fOldDescription; } + /** + * Return the new description which is writeable + * @return writable new description + */ public ICProjectDescription getNewCProjectDescription() { return fNewDescription; } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigExtensionReference.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigExtensionReference.java index 7bfa9d92b9a..bd9a78bb522 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigExtensionReference.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigExtensionReference.java @@ -10,8 +10,16 @@ *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import org.eclipse.cdt.core.ICExtensionReference; import org.eclipse.core.runtime.CoreException; +/** + * Holds executable extension information in the + * project configuration. Like ICExtensionReference + * but has knowledge of its ICConfigurationDescription + * + * @see ICExtensionReference + */ public interface ICConfigExtensionReference { /** * Return the extension point of this reference. @@ -40,7 +48,7 @@ public interface ICConfigExtensionReference { /** * Returns the project descriptor which this extension reference belongs to. - * @return the ICDescriptor + * @return the {@link ICConfigurationDescription} */ public ICConfigurationDescription getConfiguration(); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescription.java index 0225f878c10..3967c2a976a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescription.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -127,7 +128,7 @@ public interface ICProjectDescription extends ICSettingContainer, * the get/setSettionsProperty methods allow to associate the session properties with the given project description * session properties are not persisted and are not restored on the next eclipse session * the scope of project description session properties is the current project description, - * i.e. modifications to the properties are not applied untill the setProjectDescription call + * i.e. modifications to the properties are not applied until the setProjectDescription call * * @param name */ @@ -137,7 +138,7 @@ public interface ICProjectDescription extends ICSettingContainer, * the get/setSettionsProperty methods allow to associate the session properties with the given project description * session properties are not persisted and are not restored on the next eclipse session * the scope of project description session properties is the current project description, - * i.e. modifications to the properties are not applied untill the setProjectDescription call + * i.e. modifications to the properties are not applied until the setProjectDescription call * * @param name * @param value diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescriptionManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescriptionManager.java index 0d1800e5b65..c743ee791a0 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescriptionManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICProjectDescriptionManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Intel Corporation and others. + * Copyright (c) 2007, 2008 Intel 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 @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.core.settings.model; @@ -14,16 +15,58 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +/** + * This interface represents the manager of CDT Project descriptions. + */ public interface ICProjectDescriptionManager { + /* + * setProjectDescription flags + */ + /** Flag indicating that the description should be serialized even + * if the ProjectDescription isn't marked as modified. + * @see ICProjectDescriptionManager#setProjectDescription(IProject, ICProjectDescription, int, IProgressMonitor) */ public static final int SET_FORCE = 1; + /** Flag indicating that the project description shouldn't be serialized. + * @see ICProjectDescriptionManager#setProjectDescription(IProject, ICProjectDescription, int, IProgressMonitor) */ public static final int SET_NO_SERIALIZE = 1 << 1; + /* + * getProjectDescription flags + */ + + /** Flag indicating writable project description is required + * @see ICProjectDescriptionManager#getProjectDescription(IProject, int) */ public static final int GET_WRITABLE = 1 << 2; + /** Return the project description only if it's already loaded */ public static final int GET_IF_LOADDED = 1 << 3; + /** + * Flag indicating that a new empty ICProjectDescription should be created and returned + * (irrespective of whether one already exists) + */ + public static final int GET_EMPTY_PROJECT_DESCRIPTION = 1 << 4; + /** + * Flag indicating that the user has called createProjectDescription. + * i.e. a description should be returned irrespective of whether one already exists. + * If the project already has a description and !{@link #GET_EMPTY_PROJECT_DESCRIPTION} + * the existing description will be returned, otherwise a new description is returned + */ + public static final int GET_CREATE_DESCRIPTION = 1 << 5; + /** + * Flag indicating that the Project is in the process of being created (i.e. + * the user is working through the new project dialog...) This flag doesn't + * affect whether a description should or shouldn't be created. + * + * @see #GET_CREATE_DESCRIPTION + * @see ICProjectDescription#isCdtProjectCreating() + */ + public static final int PROJECT_CREATING = 1 << 6; /** - * this method is a full equivalent to {@link #createProjectDescription(IProject, boolean, false)} - * + * This method is a full equivalent to:
+ * - createProjectDescription(IProject, boolean, false)
+ * - getProjectDescription(IProject, GET_WRITABLE | loadIfExists ? 0 : GET_EMPTY_PROJECT_DESCRIPTION)
+ * and returns a writable project description which is either empty or a copy of the previous configuration description + * if loadIfExists == true. * @see #createProjectDescription(IProject, boolean, boolean) */ ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists) throws CoreException; @@ -44,8 +87,45 @@ public interface ICProjectDescriptionManager { * @throws CoreException */ ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists, boolean creating) throws CoreException; - + /** + * This method is called to save/apply the project description + * the method should be called to apply changes made to the project description + * returned by the {@link #getProjectDescription(IProject, boolean)} or {@link #createProjectDescription(IProject, boolean)} + * + * Note that having persisted changes to the description, the passed in ICProjectDescription is read-only + * and shouldn't be used. If the user wishes to continue editing the ICProjectDescription they must ensure + * they getProjectDescription again. + * + * @param project + * @param des + * @throws CoreException + * + * @see {@link #getProjectDescription(IProject, boolean)} + * @see #createProjectDescription(IProject, boolean) + */ + void setProjectDescription(IProject project, ICProjectDescription des) throws CoreException; + + /** + * This method is called to + * @param project + * @param des + * @param force + * @param monitor + * @throws CoreException + */ + void setProjectDescription(IProject project, ICProjectDescription des, boolean force, IProgressMonitor monitor) throws CoreException; + + /** + * + * @param project + * @param des + * @param flags + * @param monitor + * @throws CoreException + */ + void setProjectDescription(IProject project, ICProjectDescription des, int flags, IProgressMonitor monitor) throws CoreException; + /** * returns the project description associated with this project or null if the project does not contain the * CDT data associated with it. @@ -61,24 +141,6 @@ public interface ICProjectDescriptionManager { * @see #getProjectDescription(IProject, boolean) */ ICProjectDescription getProjectDescription(IProject project); - - /** - * this method is called to save/apply the project description - * the method should be called to apply changes made to the project description - * returned by the {@link #getProjectDescription(IProject, boolean)} or {@link #createProjectDescription(IProject, boolean)} - * - * @param project - * @param des - * @throws CoreException - * - * @see {@link #getProjectDescription(IProject, boolean)} - * @see #createProjectDescription(IProject, boolean) - */ - void setProjectDescription(IProject project, ICProjectDescription des) throws CoreException; - - void setProjectDescription(IProject project, ICProjectDescription des, boolean force, IProgressMonitor monitor) throws CoreException; - - void setProjectDescription(IProject project, ICProjectDescription des, int flags, IProgressMonitor monitor) throws CoreException; /** * returns the project description associated with this project or null if the project does not contain the @@ -94,12 +156,12 @@ public interface ICProjectDescriptionManager { * All set* calls to the read-only description result in the {@link WriteAccessException} * * When the writable description is requested, the description copy is created. - * Changes to this description will not be reflected/used by the core and Build System untill the + * Changes to this description will not be reflected/used by the core and Build System until the * {@link #setProjectDescription(IProject, ICProjectDescription)} is called * * Each getProjectDescription(project, true) returns a new copy of the project description * - * The writable description uses the cached data untill the first set call + * The writable description uses the cached data until the first set call * after that the description communicates directly to the Build System * i.e. the implementer of the org.eclipse.cdt.core.CConfigurationDataProvider extension * This ensures the Core<->Build System settings integrity @@ -108,12 +170,18 @@ public interface ICProjectDescriptionManager { * CDT data associated with it. */ ICProjectDescription getProjectDescription(IProject project, boolean write); - + + /** + * @see ICProjectDescriptionManager#createProjectDescription(IProject, boolean) + * @param project + * @param flags + * @return + */ ICProjectDescription getProjectDescription(IProject project, int flags); /** - * forces the cached data of the specified projects to be re-calculated. - * if the projects argument is null al projects + * forces the cached data of the specified projects to be re-loaded. + * if the projects argument is null all projects * within the workspace are updated * * @param projects @@ -136,8 +204,25 @@ public interface ICProjectDescriptionManager { */ boolean isNewStyleProject(ICProjectDescription des); + /** + * Register a listener for changes on the set of known ICProjectDescriptions for the specified set + * of events + * + * @param listener + * @param eventTypes see the eventTypes in {@link CProjectDescriptionEvent} + * @see CProjectDescriptionEvent#ABOUT_TO_APPLY + * @see CProjectDescriptionEvent#APPLIED + * @see CProjectDescriptionEvent#COPY_CREATED + * @see CProjectDescriptionEvent#DATA_APPLIED + * @see CProjectDescriptionEvent#LOADED + * @see CProjectDescriptionEvent#ALL + */ void addCProjectDescriptionListener(ICProjectDescriptionListener listener, int eventTypes); + /** + * Remove the listener from the set of ICProjecctDescriptionListeners + * @param listener + */ void removeCProjectDescriptionListener(ICProjectDescriptionListener listener); /** diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingsStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingsStorage.java index 5c752e1460c..1f69fd38f6a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingsStorage.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingsStorage.java @@ -7,30 +7,48 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import java.util.Map; + +import org.eclipse.cdt.core.ICDescriptor; +import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.core.settings.model.extension.CConfigurationDataProvider; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; /** - * this interface represents the settings storage that can be used for storing - * data in the tree-like format of name-value holder elements - * + * This interface represents the settings storage that can be used as the root + * of a settings tree of name-attribute-value holder elements ({@link ICStorageElement}s). + *

+ * In real terms this is a specialised node in the project description tree. It is specialised + * in that it can only contain ICStorageElements as children and has no associated attributes or + * value. The Xml model implements this as an element called 'storageModule' which contains + * other arbitrary Xml ICStorageElements. + *

* Both {@link ICProjectDescription} and {@link ICConfigurationDescription} implement this * interface thus providing the capabilities to store custom project-wide and configuration-specific - * data in the storage file (.cproject) - * - * These capabilities could be used, e.g. by the Build System - * (org.eclipse.cdt.core.CConfigurationDataProvider extension implementer) - * for loadding/storing data on the {@link CConfigurationDataProvider#loadConfiguration(ICConfigurationDescription)} - * and {@link CConfigurationDataProvider#applyConfiguration(ICConfigurationDescription, org.eclipse.cdt.core.settings.model.extension.CConfigurationData)} - * requests + * data in the storage file + *

+ * The format of the storage file is left up to the implementor. It may be an XML file + * (.cproject) a relational database (.cprojectdb) or any other format of the extenders choosing. + *

+ * These capabilities are used by the build system for persisting build configuration data + * as well as by the CoreModel {@link ICDescriptor} storage trees. See + * {@link CConfigurationDataProvider#loadConfiguration(ICConfigurationDescription, IProgressMonitor)} + * and {@link CConfigurationDataProvider#applyConfiguration(ICConfigurationDescription, ICConfigurationDescription, CConfigurationData, IProgressMonitor)} * + * @see ICStorageElement + * @see ICProjectDescription + * @see ICConfigurationDescription + * @see ICDescriptor */ public interface ICSettingsStorage { /** * returns the storage of the specified id - * @param id any custom string value uniquely representing the storage + * @param id any custom string value uniquely representing the storage * @return {@link ICStorageElement} if the settings storage does not contain the information of * the specified id an empty storage is created and returned * @throws CoreException @@ -39,13 +57,50 @@ public interface ICSettingsStorage { */ ICStorageElement getStorage(String id, boolean create) throws CoreException; -// /** -// * -// * @param id any custom string value uniquely representing the storage -// * @return true if the setting storage contains storage of the specified id and false - otherwise -// * @throws CoreException -// */ -// boolean containsStorage(String id) throws CoreException; - + /** + * Return a Map of StorageID -> ICStorageElement + * @return + */ +// Map getStorages(); + + /** + * Remove the storage module with the given ID from this ICSettingsStorage + * @param id + * @throws CoreException + */ void removeStorage(String id) throws CoreException; + + /** + * Import an existing ICStorageElement storage module into the ICSettingsStorage + * Returns a handle on the newly imported ICSettingsStorage + * + * NB Storage IDs are unique in an ICSettingsStorage. Importing a storage + * will replace any other storage with equivalent id + * @param id name of the storage to be imported + * @param el ICStorageElement to be imported + * @return ICStorageElement representing the imported storage + * @throws UnsupportedOperationException + */ + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException; + + /** + * Returns whether any non-persisted changes exist in this tree + * @return boolean indicating whether any elements in this tree have been modified + */ + public boolean isModified(); + + /** + * Return whether this Settings Storage is currently read only + * @return whether this storage is readonly + */ + public boolean isReadOnly(); + + /** + * Mark this Settings Storage as read only. If keepModify is set + * then modified flag will not be reset + * @param readOnly + * @param keepModify + */ + void setReadOnly(boolean readOnly, boolean keepModify); + } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICStorageElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICStorageElement.java index 7af41a8f089..e1a4f6e8946 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICStorageElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICStorageElement.java @@ -7,49 +7,174 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import org.eclipse.core.runtime.CoreException; + /** * - * this interface represents the abstract storage that can be used for storing - * data in the tree-like format of name-value holder elements + * This interface represents an generic element in a storage tree. These trees are rooted at + * @link{ICSettingsStorage}Elements. * * This abstract storage mechanism is used, e.g. with the {@link ICProjectDescription} and {@link ICConfigurationDescription} - * for storing custom data in the settings file (.cproject) - * + * for storing custom data in the settings file (.cproject) or in a database + * * @see ICSettingsStorage * @see ICProjectDescription * @see ICConfigurationDescription * */ public interface ICStorageElement { - ICStorageElement[] getChildren(); - + + /** + * Return the String of attribute value for name. + * If attribute is not found (hasAttribute(name) is false) + * this method returns null + * @param name + * @return String value or null if hasAttribute is false + */ String getAttribute(String name); - + + /** + * Return whether this ICStorageElement contains an attribute value + * for name + * @param name + * @return boolean indicating existence of attribute with name name + * @since 5.1 + */ + boolean hasAttribute(String name); + + /** + * Returns a string array of attribute names + * @return String[] + */ String[] getAttributeNames(); - + + /** + * Return the parent IStorageElement or null if this + * ICStorageElement doesn't have a parent + * @return ICStorageElement parent or null + */ ICStorageElement getParent(); - + + /** + * Set an attribute on this ICStorageElement + * @param name + * @param value + */ void setAttribute(String name, String value); - + + /** + * Remove an attribute from this ICStorageElement + * @param name + */ void removeAttribute(String name); - + + /** + * Create a child ICStorageElement with the given name. + * @param name + * @return new ICStorageElement representing the child + */ ICStorageElement createChild(String name); + /** + * Returns an array of the ICStorageElement children of this + * ICStorageElement or an empty array if no children were found + * @return ICStorageElement[] of children or empty array + */ + ICStorageElement[] getChildren(); + + /** + * Returns the children ICStorageElements with name name + * @param name String name of children to be returned + * @return ICStorageElement[] of children may be the empty list if no children with name found + * @since 5.1 + */ + ICStorageElement[] getChildrenByName(String name); + + /** + * Returns true if this storage element has child ICStorageElements + * @return boolean indicating whether this ICStorageElement has children + */ + boolean hasChildren(); + + /** + * Erase all children, attributes and any value set on this ICStorageElement + */ void clear(); - + + /** + * Get the name of this ICStorageElement + * @return String name + */ String getName(); - -// void remove(); - + + /** + * Remove the ICStorageElement from the set of child ICSotrageElements + * @param el + */ void removeChild(ICStorageElement el); - + + /** + * Get the String value of this element or null if there is + * no String value set. + * + * NB a pure whitespace value is considered to be null + * @return String or null + */ String getValue(); - - void setValue(String value); - + + /** + * Set a String value on the ICStorageElement + * @param value + */ + void setValue(String value); + + /** + * Import an existing ICStorageElemtn as a child of this ICStorageElement + * @param el + * @return ICStorageElement a Handle on the newly imported ICStorageElement + * @throws UnsupportedOperationException + */ ICStorageElement importChild(ICStorageElement el) throws UnsupportedOperationException; + + /** + * Create a deep copy of the current ICStorageElement such that name, children, attributes and value + * are the same. + *
+ * However this is implemented it should appear to the user that a deep copy of + * the elements within has occurred. [ Though the implementation may be copy-on-write + * if the underlying data structure is suitable. ] + *

+ * getParent() of the clone should be equal to the original element.getParent(). + * However the clone() doesn't appear in the parent's getChildren() array. + * @return ICStorageElement deep copy of this ICStorageElement + */ + ICStorageElement createCopy() throws UnsupportedOperationException, CoreException; + + /** + * Returns an ICSettingsStorage from this storage element. + * + * A setting storage is like a storage element except it represents the root of a tree. + * As such it can't contain a value or any children which are not storageModule + * ICStorageElements (otherwise they would not be accessible via the ICSettingsStorage interface) + * + * @param readOnly indicates whether the returned settings storage tree should be readonly + * @return ICSettingStorage which is this ICStorageElement as a storageModule root + * @throws CoreException if this ICStorageElement isn't a suitable root + * @throws UnsupportedOperationException if this hierarchy doesn't support ICSettingsStorage + */ +// ICSettingsStorage createSettingStorage(boolean readOnly) throws CoreException, UnsupportedOperationException; + + /** + * Tests whether this storage element is exactly equal to other + * To be equal all name, children attributes and value must be + * equal between the two ICStorageElements + * @param other + * @return boolean indicating equality + */ + boolean equals(ICStorageElement other); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/XmlStorageUtil.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/XmlStorageUtil.java new file mode 100644 index 00000000000..a8b04388450 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/XmlStorageUtil.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom Corp. 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: + * James Blackburn (Broadcom Corp.) - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.settings.model; + +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorageElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class serves as a bridge from Xml Document trees to + * ICStorageElement trees. + * + * This allows importing of old style Xml trees into ICStorageElement + * based project descriptions + */ +public class XmlStorageUtil { + + /** + * Return an ICStorageElement tree based around the specified + * document + * + * N.B. the tree is backed by the passed in document + * so care should be taken to ensure that the tree is only + * subsequently through the ICStorageElement interface + * + * The ICStorageElement tree is based on the first Element + * found in the Document + * @param doc + * @return ICStorageElement tree or null if impossible + */ + public static ICStorageElement createCStorageTree(Document doc) { + NodeList list = doc.getChildNodes(); + for (int i = 0; i < list.getLength(); i++) { + if (list.item(i).getNodeType() == Node.ELEMENT_NODE) { + return createCStorageTree((Element)list.item(i)); + } + } + return null; + } + + /** + * Return an ICStorageElement tree based around the specified + * Element. + * + * NB the returned ICStorageElement is backed by the passed in + * Element which should only be modified via the ICStorageElement + * interface subsequent to this conversion. + * + * @param doc + * @return ICStorageElement tree + */ + public static ICStorageElement createCStorageTree(Element el) { + return new XmlStorageElement(el); + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/extension/CConfigurationDataProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/extension/CConfigurationDataProvider.java index 1465ab2d682..e570a00522a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/extension/CConfigurationDataProvider.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/extension/CConfigurationDataProvider.java @@ -28,7 +28,7 @@ public abstract class CConfigurationDataProvider { /** * requests the Configuration Data to be created for the given ConfigurationDescription - * The method can be called in several caces: + * The method can be called in several cases: * 1. When the new configuration is being created based upon the already existing one via * theICProjectDescription.createConfiguration method call * 2. When the configuration copy (clone) is being created for the copy description diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/ResourceChangeHandlerBase.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/ResourceChangeHandlerBase.java index caff261452c..7988ef6c4b2 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/ResourceChangeHandlerBase.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/ResourceChangeHandlerBase.java @@ -42,7 +42,7 @@ public abstract class ResourceChangeHandlerBase implements IResourceChangeListen private class DeltaVisitor implements IResourceDeltaVisitor{ // private IResourceDelta fRootDelta; - private Map fMoveMap = new HashMap(); + private Map fMoveMap = new HashMap(); private IResourceMoveHandler fHandler; public DeltaVisitor(IResourceMoveHandler handler, IResourceDelta rootDelta){ @@ -126,7 +126,7 @@ public abstract class ResourceChangeHandlerBase implements IResourceChangeListen public void resourceChanged(IResourceChangeEvent event) { if (event.getSource() instanceof IWorkspace) { IResourceMoveHandler handler = createResourceMoveHandler(event); - doHahdleResourceMove(event, handler); + doHandleResourceMove(event, handler); } } @@ -139,7 +139,7 @@ public abstract class ResourceChangeHandlerBase implements IResourceChangeListen } } - protected void doHahdleResourceMove(IResourceChangeEvent event, IResourceMoveHandler handler){ + protected void doHandleResourceMove(IResourceChangeEvent event, IResourceMoveHandler handler){ switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: IProject project = (IProject)event.getResource(); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/LanguageMappingStore.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/LanguageMappingStore.java index 1c3d15a6849..43b1fa16e0d 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/LanguageMappingStore.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/LanguageMappingStore.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.language; @@ -33,13 +34,13 @@ import org.eclipse.cdt.core.CCorePreferenceConstants; import org.eclipse.cdt.core.ICDescriptor; import org.eclipse.cdt.core.language.ProjectLanguageConfiguration; import org.eclipse.cdt.core.language.WorkspaceLanguageConfiguration; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.internal.core.Util; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Preferences; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -53,13 +54,13 @@ public class LanguageMappingStore { private static final String PROJECT_MAPPINGS = "project-mappings"; //$NON-NLS-1$ private static final String WORKSPACE_MAPPINGS = "workspace-mappings"; //$NON-NLS-1$ - + private static final String CONTENT_TYPE_MAPPING = "content-type-mapping"; //$NON-NLS-1$ - + private static final String FILE_MAPPING = "file-mapping"; //$NON-NLS-1$ private static final String ATTRIBUTE_PATH = "path"; //$NON-NLS-1$ - + private static final String ATTRIBUTE_CONTENT_TYPE = "content-type"; //$NON-NLS-1$ private static final String ATTRIBUTE_LANGUAGE = "language"; //$NON-NLS-1$ @@ -68,31 +69,31 @@ public class LanguageMappingStore { public LanguageMappingStore() { } - + public ProjectLanguageConfiguration decodeMappings(IProject project) throws CoreException { ProjectLanguageConfiguration config = new ProjectLanguageConfiguration(); ICDescriptor descriptor = getProjectDescription(project); - Element rootElement = descriptor.getProjectData(LANGUAGE_MAPPING_ID); + ICStorageElement rootElement = descriptor.getProjectStorageElement(LANGUAGE_MAPPING_ID); if (rootElement == null) { return config; } - - NodeList mappingElements = rootElement.getElementsByTagName(PROJECT_MAPPINGS); - if (mappingElements.getLength() > 0) { - Element element = (Element) mappingElements.item(0); + + ICStorageElement[] mappingElements = rootElement.getChildrenByName(PROJECT_MAPPINGS); + if (mappingElements.length > 0) { + ICStorageElement element = mappingElements[0]; config.setContentTypeMappings(decodeProjectContentTypeMappings(element)); config.setFileMappings(decodeFileMappings(element)); } return config; } - - private Map> decodeProjectContentTypeMappings(Element rootElement) { + + private Map> decodeProjectContentTypeMappings(ICStorageElement rootElement) { Map> decodedMappings = new TreeMap>(); - NodeList mappingElements = rootElement.getElementsByTagName(CONTENT_TYPE_MAPPING); - for (int j = 0; j < mappingElements.getLength(); j++) { - Element mapping = (Element) mappingElements.item(j); + ICStorageElement[] mappingElements = rootElement.getChildrenByName(CONTENT_TYPE_MAPPING); + for (int j = 0; j < mappingElements.length; j++) { + ICStorageElement mapping = mappingElements[j]; String configuration = mapping.getAttribute(ATTRIBUTE_CONFIGURATION); - + Map contentTypeMappings = decodedMappings.get(configuration); if (contentTypeMappings == null) { contentTypeMappings = new TreeMap(); @@ -108,18 +109,18 @@ public class LanguageMappingStore { protected ICDescriptor getProjectDescription(IProject project) throws CoreException { return CCorePlugin.getDefault().getCProjectDescription(project, true); } - + private Map decodeContentTypeMappings(Element rootElement) throws CoreException { return decodeMappings(rootElement, CONTENT_TYPE_MAPPING, ATTRIBUTE_CONTENT_TYPE, ATTRIBUTE_LANGUAGE); } - - private Map> decodeFileMappings(Element rootElement) throws CoreException { + + private Map> decodeFileMappings(ICStorageElement rootElement) throws CoreException { Map> decodedMappings = new TreeMap>(); - NodeList mappingElements = rootElement.getElementsByTagName(FILE_MAPPING); - for (int j = 0; j < mappingElements.getLength(); j++) { - Element mapping = (Element) mappingElements.item(j); + ICStorageElement[] mappingElements = rootElement.getChildrenByName(FILE_MAPPING); + for (int j = 0; j < mappingElements.length; j++) { + ICStorageElement mapping = mappingElements[j]; String path = mapping.getAttribute(ATTRIBUTE_PATH); - + Map configurationMappings = decodedMappings.get(path); if (configurationMappings == null) { configurationMappings = new TreeMap(); @@ -131,7 +132,7 @@ public class LanguageMappingStore { } return decodedMappings; } - + private Map decodeMappings(Element rootElement, String category, String keyName, String valueName) { Map decodedMappings = new TreeMap(); NodeList mappingElements = rootElement.getElementsByTagName(category); @@ -146,36 +147,33 @@ public class LanguageMappingStore { public void storeMappings(IProject project, ProjectLanguageConfiguration config) throws CoreException { ICDescriptor descriptor = getProjectDescription(project); - Element rootElement = descriptor.getProjectData(LANGUAGE_MAPPING_ID); - clearChildren(rootElement); + ICStorageElement rootElement = descriptor.getProjectStorageElement(LANGUAGE_MAPPING_ID); + // clear all children and settings + rootElement.clear(); + + ICStorageElement projectMappings = rootElement.createChild(PROJECT_MAPPINGS); - Document document = rootElement.getOwnerDocument(); - Element projectMappings = document.createElement(PROJECT_MAPPINGS); - rootElement.appendChild(projectMappings); - addProjectContentTypeMappings(config.getContentTypeMappings(), projectMappings); addFileMappings(config.getFileMappings(), projectMappings); descriptor.saveProjectData(); } - private void addProjectContentTypeMappings(Map> contentTypeMappings, Element rootElement) { - Document document = rootElement.getOwnerDocument(); + private void addProjectContentTypeMappings(Map> contentTypeMappings, ICStorageElement rootElement) { Iterator>> entries = contentTypeMappings.entrySet().iterator(); while (entries.hasNext()) { Entry> entry = entries.next(); - + String configuration = entry.getKey(); Iterator> contentTypeEntries = entry.getValue().entrySet().iterator(); while (contentTypeEntries.hasNext()) { Entry configurationEntry = contentTypeEntries.next(); String contentType = configurationEntry.getKey(); String language = configurationEntry.getValue(); - - Element mapping = document.createElement(CONTENT_TYPE_MAPPING); + + ICStorageElement mapping = rootElement.createChild(CONTENT_TYPE_MAPPING); mapping.setAttribute(ATTRIBUTE_CONTENT_TYPE, contentType); mapping.setAttribute(ATTRIBUTE_CONFIGURATION, configuration); mapping.setAttribute(ATTRIBUTE_LANGUAGE, language); - rootElement.appendChild(mapping); } } } @@ -193,7 +191,7 @@ public class LanguageMappingStore { StreamResult result = new StreamResult(buffer); serializer.transform(source, result); String encodedMappings = buffer.getBuffer().toString(); - + Preferences node = CCorePlugin.getDefault().getPluginPreferences(); node.setValue(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS, encodedMappings); CCorePlugin.getDefault().savePluginPreferences(); @@ -201,18 +199,18 @@ public class LanguageMappingStore { throw new CoreException(Util.createStatus(e)); } catch (TransformerException e) { throw new CoreException(Util.createStatus(e)); - } + } } - + public WorkspaceLanguageConfiguration decodeWorkspaceMappings() throws CoreException { Preferences node = CCorePlugin.getDefault().getPluginPreferences(); String encodedMappings = node.getString(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS); WorkspaceLanguageConfiguration config = new WorkspaceLanguageConfiguration(); - + if (encodedMappings == null || encodedMappings.length() == 0) { return config; } - + // The mappings are encoded as XML in a String so we need to parse it. InputSource input = new InputSource(new StringReader(encodedMappings)); try { @@ -227,7 +225,7 @@ public class LanguageMappingStore { throw new CoreException(Util.createStatus(e)); } } - + private Transformer createSerializer() throws CoreException { try { return TransformerFactory.newInstance().newTransformer(); @@ -238,14 +236,6 @@ public class LanguageMappingStore { } } - private void clearChildren(Element element) { - Node child = element.getFirstChild(); - while (child != null) { - element.removeChild(child); - child = element.getFirstChild(); - } - } - private void addMappings(Map mappings, Element rootElement, String category, String keyName, String valueName) { Document document = rootElement.getOwnerDocument(); Iterator> entries = mappings.entrySet().iterator(); @@ -257,29 +247,22 @@ public class LanguageMappingStore { rootElement.appendChild(mapping); } } - + private void addContentTypeMappings(Map mappings, Element rootElement) { addMappings(mappings, rootElement, CONTENT_TYPE_MAPPING, ATTRIBUTE_CONTENT_TYPE, ATTRIBUTE_LANGUAGE); } - - private void addFileMappings(Map> mappings, Element rootElement) { - Document document = rootElement.getOwnerDocument(); - Iterator>> entries = mappings.entrySet().iterator(); - while (entries.hasNext()) { - Entry> entry = entries.next(); - Element mapping = document.createElement(FILE_MAPPING); - + + private void addFileMappings(Map> mappings, ICStorageElement rootElement) { + for (Map.Entry> entry : mappings.entrySet()) { + ICStorageElement mapping = rootElement.createChild(FILE_MAPPING); String path = entry.getKey(); - Iterator> configurationEntries = entry.getValue().entrySet().iterator(); - while (configurationEntries.hasNext()) { - Entry configurationEntry = configurationEntries.next(); + for (Entry configurationEntry : entry.getValue().entrySet()) { String configuration = configurationEntry.getKey(); String language = configurationEntry.getValue(); - + mapping.setAttribute(ATTRIBUTE_PATH, path); mapping.setAttribute(ATTRIBUTE_CONFIGURATION, configuration); mapping.setAttribute(ATTRIBUTE_LANGUAGE, language); - rootElement.appendChild(mapping); } } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/APathEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/APathEntry.java index f5453be7c5a..ffde394f52b 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/APathEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/APathEntry.java @@ -12,6 +12,7 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.model; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -123,6 +124,16 @@ public abstract class APathEntry extends PathEntry { } return super.equals(obj); } + + @Override + public int hashCode() { + int hashCode = Arrays.hashCode(exclusionPatterns); + if (basePath != null) + hashCode += basePath.hashCode(); + if (baseRef != null) + hashCode += baseRef.hashCode(); + return hashCode + super.hashCode(); + } /* (non-Javadoc) * @see java.lang.Object#toString() diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java index d6cf33aea81..8e37b1bb659 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java @@ -161,27 +161,32 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe public static final IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0]; - static CModelManager factory = null; + static volatile CModelManager factory = null; private CModelManager() { } public static CModelManager getDefault() { if (factory == null) { - factory = new CModelManager(); + synchronized (CModelManager.class) { + if (factory != null) + return factory; - // Register to the workspace; - ResourcesPlugin.getWorkspace().addResourceChangeListener(factory, - IResourceChangeEvent.POST_CHANGE - | IResourceChangeEvent.PRE_DELETE - | IResourceChangeEvent.PRE_CLOSE); + factory = new CModelManager(); - // Register the Core Model on the Descriptor - // Manager, it needs to know about changes. - CCorePlugin.getDefault().getCDescriptorManager().addDescriptorListener(factory); - // Register the Core Model on the ContentTypeManager - // it needs to know about changes. - Platform.getContentTypeManager().addContentTypeChangeListener(factory); + // Register to the workspace; + ResourcesPlugin.getWorkspace().addResourceChangeListener(factory, + IResourceChangeEvent.POST_CHANGE + | IResourceChangeEvent.PRE_DELETE + | IResourceChangeEvent.PRE_CLOSE); + + // Register the Core Model on the Descriptor + // Manager, it needs to know about changes. + CCorePlugin.getDefault().getCDescriptorManager().addDescriptorListener(factory); + // Register the Core Model on the ContentTypeManager + // it needs to know about changes. + Platform.getContentTypeManager().addContentTypeChangeListener(factory); + } } return factory; } @@ -1153,8 +1158,8 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe } } - for (ICElement element : newElements.keySet()) - this.cache.putInfo(element, newElements.get(element)); + for (Map.Entry element : newElements.entrySet()) + this.cache.putInfo(element.getKey(), element.getValue()); } /** @@ -1212,10 +1217,10 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe } /** - * + * */ public void startup() { - // Do any initialization. + // Initialization is performed on the first getDefault()... } /** @@ -1234,6 +1239,9 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe for (BinaryRunner runner : runners) { runner.stop(); } + + // Nullify the static factory + factory = null; } private void checkForProjectRename(IResourceDelta delta) { diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelOperation.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelOperation.java index 390541b7a06..2db525cbe2f 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelOperation.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelOperation.java @@ -13,6 +13,8 @@ package org.eclipse.cdt.internal.core.model; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.ElementChangedEvent; @@ -64,7 +66,7 @@ public abstract class CModelOperation implements IWorkspaceRunnable, IProgressMo * empty result if no elements are created, or if this * operation is not actually executed. */ - protected static ICElement[] fgEmptyResult= new ICElement[] {}; + protected static final ICElement[] fgEmptyResult= new ICElement[] {}; /** * Collection of ICElementDeltas created by this operation. @@ -73,7 +75,7 @@ public abstract class CModelOperation implements IWorkspaceRunnable, IProgressMo * deltas. This collection is registered with the C Model notification * manager if the operation completes successfully. */ - protected ICElementDelta[] fDeltas= null; + protected List fDeltas= null; /** * The elements created by this operation - empty @@ -105,7 +107,7 @@ public abstract class CModelOperation implements IWorkspaceRunnable, IProgressMo /* * A per thread stack of java model operations (PerThreadObject of ArrayList). */ - protected static ThreadLocal> operationStacks = new ThreadLocal>(); + protected final static ThreadLocal> operationStacks = new ThreadLocal>(); protected CModelOperation() { } @@ -163,14 +165,9 @@ public abstract class CModelOperation implements IWorkspaceRunnable, IProgressMo * when the operation completes. */ protected void addDelta(ICElementDelta delta) { - if (fDeltas == null) { - fDeltas= new ICElementDelta[] {delta}; - } else { - ICElementDelta[] copy= new ICElementDelta[fDeltas.length + 1]; - System.arraycopy(fDeltas, 0, copy, 0, fDeltas.length); - copy[fDeltas.length]= delta; - fDeltas= copy; - } + if (fDeltas == null) + fDeltas = new LinkedList(); + fDeltas.add(delta); } /* diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java index 549f169bbaf..99e866944ff 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java @@ -324,15 +324,13 @@ public class CProject extends Openable implements ICProject { setPreferences(preferences); // always reset (26255) if (newOptions != null) { - Iterator keys = newOptions.keySet().iterator(); - - while (keys.hasNext()) { - String key = keys.next(); + for (Map.Entry e : newOptions.entrySet()) { + String key = e.getKey(); if (!CModelManager.OptionNames.contains(key)) continue; // unrecognized option // no filtering for encoding (custom encoding for project is allowed) - String value = newOptions.get(key); + String value = e.getValue(); preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251) preferences.setValue(key, value); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/DefaultPathEntryStore.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/DefaultPathEntryStore.java index c23d5704378..ef0b1ab0325 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/DefaultPathEntryStore.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/DefaultPathEntryStore.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.model; @@ -33,6 +34,8 @@ import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.cdt.core.resources.IPathEntryStore; import org.eclipse.cdt.core.resources.IPathEntryStoreListener; import org.eclipse.cdt.core.resources.PathEntryStoreChangedEvent; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.internal.core.CharOperation; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -89,16 +92,9 @@ public class DefaultPathEntryStore implements IPathEntryStore, ICDescriptorListe ICDescriptor cdesc = CCorePlugin.getDefault().getCProjectDescription(fProject, false); if (cdesc != null) { ArrayList pathEntries = new ArrayList(); - Element element = cdesc.getProjectData(PATH_ENTRY_ID); - NodeList list = element.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - Node childNode = list.item(i); - if (childNode != null && childNode.getNodeType() == Node.ELEMENT_NODE) { - if (childNode.getNodeName().equals(PATH_ENTRY)) { - pathEntries.add(decodePathEntry(fProject, (Element) childNode)); - } - } - } + ICStorageElement entry = cdesc.getProjectStorageElement(PATH_ENTRY_ID); + for (ICStorageElement childNode : entry.getChildrenByName(PATH_ENTRY)) + pathEntries.add(decodePathEntry(fProject, childNode)); IPathEntry[] entries = new IPathEntry[pathEntries.size()]; pathEntries.toArray(entries); return entries; @@ -111,23 +107,18 @@ public class DefaultPathEntryStore implements IPathEntryStore, ICDescriptorListe return; } ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(fProject, true); - Element rootElement = descriptor.getProjectData(PATH_ENTRY_ID); + ICStorageElement rootElement = descriptor.getProjectStorageElement(PATH_ENTRY_ID); // Clear out all current children - Node child = rootElement.getFirstChild(); - while (child != null) { - rootElement.removeChild(child); - child = rootElement.getFirstChild(); - } + rootElement.clear(); // Save the entries if (newRawEntries != null && newRawEntries.length > 0) { // Serialize the include paths - Document doc = rootElement.getOwnerDocument(); - encodePathEntries(fProject.getFullPath(), doc, rootElement, newRawEntries); + encodePathEntries(fProject.getFullPath(), rootElement, newRawEntries); } descriptor.saveProjectData(); } - static IPathEntry decodePathEntry(IProject project, Element element) throws CModelException { + static IPathEntry decodePathEntry(IProject project, ICStorageElement element) throws CModelException { IPath projectPath = project.getFullPath(); // kind @@ -152,10 +143,10 @@ public class DefaultPathEntryStore implements IPathEntryStore, ICDescriptorListe } // check fo the base path - IPath basePath = new Path(element.getAttribute(ATTRIBUTE_BASE_PATH)); + IPath basePath = new Path(element.hasAttribute(ATTRIBUTE_BASE_PATH) ? element.getAttribute(ATTRIBUTE_BASE_PATH) : ""); // get the base ref - IPath baseRef = new Path(element.getAttribute(ATTRIBUTE_BASE_REF)); + IPath baseRef = new Path(element.hasAttribute(ATTRIBUTE_BASE_REF) ? element.getAttribute(ATTRIBUTE_BASE_REF) : ""); // exclusion patterns (optional) String exclusion = element.getAttribute(ATTRIBUTE_EXCLUDING); @@ -245,12 +236,11 @@ public class DefaultPathEntryStore implements IPathEntryStore, ICDescriptorListe } } - static void encodePathEntries(IPath projectPath, Document doc, Element configRootElement, IPathEntry[] entries) { - Element element; + static void encodePathEntries(IPath projectPath, ICStorageElement configRootElement, IPathEntry[] entries) { + ICStorageElement element; for (IPathEntry entrie : entries) { - element = doc.createElement(PATH_ENTRY); - configRootElement.appendChild(element); + element = configRootElement.createChild(PATH_ENTRY); int kind = entrie.getEntryKind(); // Set the kind element.setAttribute(ATTRIBUTE_KIND, PathEntry.kindToString(kind)); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MacroEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MacroEntry.java index 781be59c740..b72fde18733 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MacroEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MacroEntry.java @@ -73,6 +73,11 @@ public class MacroEntry extends APathEntry implements IMacroEntry { } return super.equals(obj); } + + @Override + public int hashCode() { + return macroName.hashCode() + macroValue.hashCode() + super.hashCode(); + } /* (non-Javadoc) * @see java.lang.Object#toString() diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MultiOperation.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MultiOperation.java index b01beb04bc7..0ff02125848 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MultiOperation.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/MultiOperation.java @@ -180,9 +180,10 @@ public abstract class MultiOperation extends CModelOperation { insertedTree = true; } } - if (insertedTree) - fDeltas = new ICElementDelta[] {rootDelta}; - else + if (insertedTree) { + fDeltas.clear(); + fDeltas.add(rootDelta); + } else fDeltas = null; } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntry.java index 3d473077051..dbb6d3bb142 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntry.java @@ -70,6 +70,11 @@ public class PathEntry implements IPathEntry { } return super.equals(obj); } + + @Override + public int hashCode() { + return path.hashCode() + entryKind * 17 + (isExported ? 3 : 2); + } /** * Returns the kind from its String form. diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/AbstractCProjectDescriptionStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/AbstractCProjectDescriptionStorage.java new file mode 100644 index 00000000000..48743c81aac --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/AbstractCProjectDescriptionStorage.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.internal.core.settings.model; + +import java.text.MessageFormat; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent; +import org.eclipse.cdt.core.settings.model.ICDescriptionDelta; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.settings.model.ICSettingsStorage; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.internal.core.model.CModelManager; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType.CProjectDescriptionStorageTypeProxy; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.osgi.framework.Version; + +/** + * This abstract class provides an extension point for functionality for loading + * a CDT Project Description from some kind of backing store. This allows + * extenders to provide their own backing store for a CDT project description. + * + * This class provides the ICProjectDescription root of the project configuration tree in + * which is contained storage modules and other members of the storage element tree. + * + * It is the responsibility of the storage that access to the project storage are threadsafe + * i.e. return writable descriptions aren't shared between multiple threads (or if they + * are, they are suitable synchronized) and setProjectDescription must be aware that + * getProjectDescription may also be called concurrently + * + *

+ * EXPERIMENTAL. This class or interface 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 CDT team. + *

+ * + * @since 6.0 + */ +public abstract class AbstractCProjectDescriptionStorage { + + /** The {@link ICProjectDescriptionStorageType} extension parent of this */ + public final CProjectDescriptionStorageTypeProxy type; + /** The version of the project description storage that was loaded */ + public final Version version; + + /** The project this project-storage is responsible for */ + protected volatile IProject project; + + /** Flag used to detect if setProjectDescription(...) is called by the thread already in a setProjectDescription(...) */ + final private ThreadLocal setProjectDescriptionOperationRunning = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return false; + } + }; + /** Before the description is fully applied / loaded, consumers of CProjectDescriptionEvent and CProjectDescription.applyDatas() + * assume that getProjectDescription(...) will return the writable project description in the process of being created / modified... + * Cached temporarily in a thread local variable for this very purpose. */ + final private ThreadLocal currentThreadProjectDescription = new ThreadLocal(); + + + /** + * @param type CProjectDescriptionStorageTypeProxy + * @param project IProject + * @param version Version + */ + public AbstractCProjectDescriptionStorage(CProjectDescriptionStorageTypeProxy type, IProject project, Version version) { + this.type = type; + this.project = project; + this.version = version; + } + + /** + * Returns the project associated with this storage + * @return the IProject associated with the current project + */ + public final IProject getProject() { + return project; + } + + /** + * Called in response to a project move event + * @param newProject + * @param oldProject + */ + public void handleProjectMove(IProject newProject, IProject oldProject) { + project = newProject; + } + + /** + * Return an ICSettingsStorage root for the given ICStorageElement + * @param element + * @return ICSettingsStorage based off of ICStorageElement + */ + public abstract ICSettingsStorage getStorageForElement(ICStorageElement element) throws CoreException; + + + /* + * T O C L E A N U P + */ + + /* + * FIXME REMOVE + * + * We shouldn't have this in this interface, but SetCProjectDescription creates + * a new description based on an existing description for the delta event. It reconciles + * them later. But this will be non-optimal for most backends + * + * Returns a 'writable' ICStorageElement tree clone of el + */ + public ICStorageElement copyElement(ICStorageElement el, boolean writable) throws CoreException { + return null; + } + + + /* + * get/setProjectDescription methods + */ + + /** + * Return the ICProjectDescription for the specified project. + * + * Use the ICProjectDescriptionManager flags to control the project + * description to be returned + * + * Implementors should call super.getProjectDescription(...) first + * so that current 'threadLocal' project description is returned + * + * @param flags Or of {@link ICProjectDescriptionManager} flags + * @param monitor + * @return an ICProjectDescription corresponding to the given + * @see ICProjectDescriptionManager#GET_WRITABLE + * @see ICProjectDescriptionManager#GET_IF_LOADDED + * @see ICProjectDescriptionManager#GET_EMPTY_PROJECT_DESCRIPTION + * @see ICProjectDescriptionManager#GET_CREATE_DESCRIPTION + * @see ICProjectDescriptionManager#PROJECT_CREATING + */ + public ICProjectDescription getProjectDescription(int flags, IProgressMonitor monitor) throws CoreException { + if (!project.isAccessible()) + throw ExceptionFactory.createCoreException(MessageFormat.format(CCorePlugin.getResourceString("ProjectDescription.ProjectNotAccessible"), getProject().getName())); //$NON-NLS-1$ + return currentThreadProjectDescription.get(); + } + + /** + * The method called by the CProjectDescriptionManager for serializing the project settings + * @param description the project description being set + * @param flags + * @param monitor + * @throws CoreException + */ + public void setProjectDescription(final ICProjectDescription description, final int flags, IProgressMonitor monitor) throws CoreException { + try { + if (monitor == null) + monitor = new NullProgressMonitor(); + + ICProject cproject = CModelManager.getDefault().create(project); + + // The CProjectDescriptionOperation fires the appropriate CElementDeltas calling the callbacks + // below for actual project serialization + SetCProjectDescriptionOperation op = new SetCProjectDescriptionOperation(this, cproject, (CProjectDescription)description, flags); + + // Safety: Verify that the listeners of the event call-backs don't recursively call setProjectDescription(...) + // While in the past this recursion hasn't been infinite, the behaviour is 'undefined'. + if (setProjectDescriptionOperationRunning.get()) { + CCorePlugin.log("API Error: setProjectDescription() shouldn't be called recursively.", new Exception()); //$NON-NLS-1$ + Job j = new Job("setProjectDescription rescheduled") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + setProjectDescription(description, flags, monitor); + } catch (CoreException e) { + CCorePlugin.log(e); + } + return Status.OK_STATUS; + } + }; + j.setSystem(true); + j.schedule(); + return; + } + + try { + setProjectDescriptionOperationRunning.set(true); + op.runOperation(monitor); + } catch (IllegalArgumentException e) { + throw ExceptionFactory.createCoreException(e); + } finally { + setProjectDescriptionOperationRunning.set(false); + } + } finally { + monitor.done(); + } + } + + + /* + * C A L L B A C K S + * Callbacks for the SetCProjectDescriptionOperation to allow AbstractCProjectDescriptionStorage overrides + * + */ + + /** + * Callback + * + * - Actually set the current in memory ICProjectDescription to this + * - If this requires modification of workspace resources then don't serialize + * + * @param des + * @param overwriteIfExists + * @return boolean indicating whether existing read-only project description should be replaced + */ + public abstract boolean setCurrentDescription(ICProjectDescription des, boolean overwriteIfExists); + + /** + * Callback + * - Return an IWorkspaceRunnable which will actually perform the serialization of the + * current project description or null if not required + * @return IWorkspaceRunnable that will perform the serialization + */ + public abstract IWorkspaceRunnable createDesSerializationRunnable() throws CoreException; + + + + /* + * R E S O U R C E C H A N G E E V E N T S + */ + + /** + * Event fired as a result of a project being moved + */ + public void projectMove(IProject newProject) { + project = newProject; + } + + /** + * Event fired as a result of the project being closed or removed + * to allow cleanup of state + */ + public void projectCloseRemove() { + // NOP + } + + /* + * C P R O J E C T D E L T A E V E N T S F I R E D + * Protected methods for notifying project description listeners of changes to the proj desc + */ + + public static final void fireLoadedEvent(ICProjectDescription desc) { + CProjectDescriptionManager.getInstance().notifyListeners(new CProjectDescriptionEvent(CProjectDescriptionEvent.LOADED, null, desc, null, null)); + } + + /** + * Fire an event stating that a copy of a description has been created + * + * This is fired when: + * - New writable description is created from read-only store + * @param newDes The new description copy + * @param oldDes The old description + */ + public static final void fireCopyCreatedEvent(ICProjectDescription newDes, ICProjectDescription oldDes) { + CProjectDescriptionManager.getInstance().notifyListeners(new CProjectDescriptionEvent(CProjectDescriptionEvent.COPY_CREATED, null, newDes, oldDes, null)); + } + + public static final void fireAboutToApplyEvent(ICProjectDescription newDes, ICProjectDescription oldDes) { + CProjectDescriptionManager.getInstance().notifyListeners(new CProjectDescriptionEvent(CProjectDescriptionEvent.ABOUT_TO_APPLY, null, newDes, oldDes, null)); + } + + public static final CProjectDescriptionEvent createAppliedEvent(ICProjectDescription newDes, ICProjectDescription oldDes, ICProjectDescription appliedDes, ICDescriptionDelta delta) { + return new CProjectDescriptionEvent(CProjectDescriptionEvent.APPLIED, delta, newDes, oldDes, appliedDes); + } + + public static final void fireAppliedEvent(ICProjectDescription newDes, ICProjectDescription oldDes, ICProjectDescription appliedDes, ICDescriptionDelta delta) { + CProjectDescriptionManager.getInstance().notifyListeners(createAppliedEvent(newDes, oldDes, appliedDes, delta)); + } + + /** + * @param newDes - a *writeable* description + * @param oldDes + * @param appliedDes - the description being applied + * @param delta + */ + public static final void fireDataAppliedEvent(ICProjectDescription newDes, ICProjectDescription oldDes, ICProjectDescription appliedDes, ICDescriptionDelta delta) { + CProjectDescriptionManager.getInstance().notifyListeners(new CProjectDescriptionEvent(CProjectDescriptionEvent.DATA_APPLIED, delta, newDes, oldDes, appliedDes)); + } + + /** + * Helper method to check whether the specified flags are set + * @param flags + * @param check + * @return boolean indicating whether flags are set + */ + protected static final boolean checkFlags(int flags, int check){ + return (flags & check) == check; + } + + /** + * Set the threadLocal project description + * + * Only intended to be used by implementors and package. + * + * This should be used in the following pattern: + * try { + * setThreadLocaProjectDesc(prjDesc); + * fireEvent(); + * } finally { + * setThreadLocalProjectDesc(null); + * } + * + * @param currentDesc + * @return the previously set thread local project desc (or null) + */ + public ICProjectDescription setThreadLocalProjectDesc(ICProjectDescription currentDesc) { + ICProjectDescription current = currentThreadProjectDescription.get(); + currentThreadProjectDescription.set(currentDesc); + return current; + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDataProviderDescriptor.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDataProviderDescriptor.java index 2d8eb4727ca..b1ae62263e7 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDataProviderDescriptor.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDataProviderDescriptor.java @@ -38,7 +38,7 @@ public class CConfigurationDataProviderDescriptor { private String[] fNatureIds; private String[] fConflictingNatureIds; - CConfigurationDataProviderDescriptor(IExtension extension){ + public CConfigurationDataProviderDescriptor(IExtension extension){ fId = extension.getUniqueIdentifier(); fExtension = extension; fProviderElement = getProviderElement(extension); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java index 7dfefa60250..c153352c366 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java @@ -30,6 +30,7 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.core.settings.model.ICSettingBase; import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingsStorage; import org.eclipse.cdt.core.settings.model.ICSourceEntry; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.ICTargetPlatformSetting; @@ -44,6 +45,7 @@ import org.eclipse.cdt.core.settings.model.extension.CResourceData; import org.eclipse.cdt.core.settings.model.extension.CTargetPlatformData; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.internal.core.settings.model.xml.InternalXmlStorageElement; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -333,12 +335,20 @@ public class CConfigurationDescription extends CDataProxyContainer implements IC return getSpecSettings().getStorage(id, create); } + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException { + return getSpecSettings().importStorage(id, el); + } + public void removeStorage(String id) throws CoreException { getSpecSettings().removeStorage(id); } - public boolean containsStorage(String id) throws CoreException { - return getSpecSettings().containsStorage(id); + public void setReadOnly(boolean readOnly, boolean keepModify) { + try { + getSpecSettings().setReadOnly(readOnly, keepModify); + } catch (CoreException e) { + CCorePlugin.log(e); + } } public CConfigurationSpecSettings getSpecSettings() throws CoreException{ diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java index a3530d7675f..e2ee9b9d29a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java @@ -58,7 +58,7 @@ public class CConfigurationDescriptionCache extends CDefaultConfigurationData private CProjectDescription fParent; private PathSettingsContainer fPathSettingContainer = PathSettingsContainer.createRootContainer(); private ResourceDescriptionHolder fRcHolder = new ResourceDescriptionHolder(fPathSettingContainer, true); - private List fChildList = new ArrayList(); + private List fChildList = new ArrayList(); private CConfigurationSpecSettings fSpecSettings; private CConfigurationData fData; private CConfigurationDescriptionCache fBaseCache; @@ -270,7 +270,7 @@ public class CConfigurationDescriptionCache extends CDefaultConfigurationData } public ICSettingObject[] getChildSettings() { - return (ICSettingObject[])fChildList.toArray(new ICSettingObject[fChildList.size()]); + return fChildList.toArray(new ICSettingObject[fChildList.size()]); } public ICConfigurationDescription getConfiguration() { @@ -292,9 +292,9 @@ public class CConfigurationDescriptionCache extends CDefaultConfigurationData public void removeStorage(String id) throws CoreException { getSpecSettings().removeStorage(id); } - - public boolean containsStorage(String id) throws CoreException { - return getSpecSettings().containsStorage(id); + + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException { + return getSpecSettings().importStorage(id, el); } public CConfigurationSpecSettings getSpecSettings() /*throws CoreException*/{ @@ -349,6 +349,11 @@ public class CConfigurationDescriptionCache extends CDefaultConfigurationData return !fInitializing; } + public void setReadOnly(boolean readOnly, boolean keepModify) { + if (readOnly) + throw ExceptionFactory.createIsReadOnlyException(); + } + public ICTargetPlatformSetting getTargetPlatformSetting() { return (ICTargetPlatformSetting)getTargetPlatformData(); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java index 5270057e1cf..a5b44c2282f 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; @@ -35,10 +36,19 @@ import org.eclipse.cdt.internal.core.CExtensionInfo; import org.eclipse.cdt.internal.core.COwner; import org.eclipse.cdt.internal.core.COwnerConfiguration; import org.eclipse.cdt.internal.core.cdtvariables.StorableCdtVariables; +import org.eclipse.cdt.internal.core.settings.model.xml.InternalXmlStorageElement; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorage; import org.eclipse.cdt.utils.envvar.StorableEnvironment; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.QualifiedName; +/** + * CConfigurationSpecSettings impelements ICSettingsStorage + * to provide storage for ICStorageElements related to project settings + * + * This corresponds to the fRefMapCache; private CExternalSettingsHolder fExtSettingsProvider = new CExternalSettingsHolder(); private boolean fIsModified; - private HashMap fSessionPropertiesMap; - private HashMap fExtMap; - private HashMap fExtInfoMap = new HashMap(); + private HashMap fSessionPropertiesMap; + private HashMap fExtMap; + private HashMap fExtInfoMap = new HashMap(); private String fOwnerId; private COwner fOwner; // private CConfigBasedDescriptor fDescriptor; @@ -129,6 +139,12 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ this(des, base, null); } + /** + * Create a new CConfigurationSpecSettings based on a base cfg spec settings + * @param des + * @param base + * @param rootEl + */ public CConfigurationSpecSettings(ICConfigurationDescription des, CConfigurationSpecSettings base, ICStorageElement rootEl){ fCfg = des; fRootStorageElement = rootEl; @@ -145,7 +161,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ fExtSettingsProvider = new CExternalSettingsHolder(base.fExtSettingsProvider); if(base.fSessionPropertiesMap != null) - fSessionPropertiesMap = (HashMap)base.fSessionPropertiesMap.clone(); + fSessionPropertiesMap = (HashMap)base.fSessionPropertiesMap.clone(); if(base.fEnvironment != null) fEnvironment = new StorableEnvironment(base.fEnvironment, des.isReadOnly()); @@ -237,7 +253,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ private ICStorageElement getSettingsStorageElement() throws CoreException{ if(fSettingsStorageElement == null) - fSettingsStorageElement =getStorage(CProjectDescriptionManager.MODULE_ID, true); + fSettingsStorageElement = getStorage(CProjectDescriptionManager.MODULE_ID, true); return fSettingsStorageElement; } @@ -249,10 +265,6 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ getStorageBase().removeStorage(id); } - public boolean containsStorage(String id) throws CoreException { - return getStorageBase().containsStorage(id); - } - ICStorageElement getRootStorageElement() throws CoreException{ if(fRootStorageElement == null){ if(fCfg.isPreferenceConfiguration()){ @@ -267,24 +279,22 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ void removeConfiguration() throws CoreException{ CProjectDescriptionManager.getInstance().removeStorage(fCfg.getProjectDescription(), fCfg.getId()); } - private CStorage getStorageBase() throws CoreException{ - if(fStorage == null){ - fStorage = new CStorage((InternalXmlStorageElement)getRootStorageElement()); -// if(fDescriptor != null) -// reconcileDescriptor(fStorage, fDescriptor); - } + + private ICSettingsStorage getStorageBase() throws CoreException{ + if(fStorage == null) + if (fCfg.isPreferenceConfiguration()) + // Get a storage from the root storage element (in the case of a preferences element, getProject() will be null... + fStorage = CProjectDescriptionManager.getInstance().getStorageForElement(null, getRootStorageElement()); + else + fStorage = CProjectDescriptionManager.getInstance().getStorageForElement(fCfg.getProjectDescription().getProject(), getRootStorageElement()); + return fStorage; } void doneInitialization(){ - if(isReadOnly()){ - if(fRootStorageElement != null) - ((InternalXmlStorageElement)fRootStorageElement).setReadOnly(true, false); - if(fSettingsStorageElement != null) - ((InternalXmlStorageElement)fSettingsStorageElement).setReadOnly(true, false); + if(isReadOnly()) if(fStorage != null) fStorage.setReadOnly(true, false); - } } public String getBuildSystemId(){ @@ -372,7 +382,11 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ public boolean isReadOnly(){ return fCfg.isReadOnly(); } - + + public void setReadOnly(boolean readOnly, boolean keepModify) { + fCfg.setReadOnly(readOnly, keepModify); + } + public StorableCdtVariables getMacros(){ if(fMacros == null) fMacros = new StorableCdtVariables(isReadOnly()); @@ -506,21 +520,21 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ setModified(true); } - private Map getSessionPropertiesMap(boolean create){ + private Map getSessionPropertiesMap(boolean create){ if(fSessionPropertiesMap == null && create) - fSessionPropertiesMap = new HashMap(); + fSessionPropertiesMap = new HashMap(); return fSessionPropertiesMap; } public Object getSettionProperty(QualifiedName name){ - Map map = getSessionPropertiesMap(false); + Map map = getSessionPropertiesMap(false); return map != null ? map.get(name) : null; } public void setSettionProperty(QualifiedName name, Object value){ // if(isReadOnly()) // throw ExceptionFactory.createIsReadOnlyException(); - Map map = getSessionPropertiesMap(true); + Map map = getSessionPropertiesMap(true); if(value != null) map.put(name, value); else @@ -530,18 +544,18 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ //extension reference info - private HashMap getExtMap(){ + private HashMap getExtMap(){ if(fExtMap == null) - fExtMap = new HashMap(); + fExtMap = new HashMap(); return fExtMap; } - public Map getExtensionMapCopy(){ - return (HashMap)getExtMap().clone(); + public Map getExtensionMapCopy(){ + return (HashMap)getExtMap().clone(); } private ICConfigExtensionReference[] doGet(String extensionPointID){ - return (CConfigExtensionReference[])getExtMap().get(extensionPointID); + return getExtMap().get(extensionPointID); } @@ -634,7 +648,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ // } private CConfigExtensionReference createRef(String extensionPoint, String extension) { - CConfigExtensionReference extensions[] = (CConfigExtensionReference[])getExtMap().get(extensionPoint); + CConfigExtensionReference extensions[] = getExtMap().get(extensionPoint); if (extensions == null) { extensions = new CConfigExtensionReference[1]; getExtMap().put(extensionPoint, extensions); @@ -680,7 +694,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ public void doRemove(ICConfigExtensionReference ext) throws CoreException { // boolean fireEvent = false; // synchronized (this) { - CConfigExtensionReference extensions[] = (CConfigExtensionReference[])getExtMap().get(ext.getExtensionPoint()); + CConfigExtensionReference extensions[] = getExtMap().get(ext.getExtensionPoint()); for (int i = 0; i < extensions.length; i++) { if (extensions[i] == ext) { // System.arraycopy(extensions, i, extensions, i + 1, extensions.length - 1 - i); @@ -713,7 +727,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ private boolean doRemove(String extensionPoint) throws CoreException { // boolean fireEvent = false; // synchronized (this) { - CConfigExtensionReference extensions[] = (CConfigExtensionReference[])getExtMap().get(extensionPoint); + CConfigExtensionReference extensions[] = getExtMap().get(extensionPoint); if (extensions != null) { getExtMap().remove(extensionPoint); return true; @@ -740,7 +754,7 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ } CExtensionInfo getInfo(CConfigExtensionReference cProjectExtension) { - CExtensionInfo info = (CExtensionInfo)fExtInfoMap.get(cProjectExtension); + CExtensionInfo info = fExtInfoMap.get(cProjectExtension); if (info == null) { info = new CExtensionInfo(); fExtInfoMap.put(cProjectExtension, info); @@ -787,14 +801,14 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ private void encodeProjectExtensions(ICStorageElement configRootElement) { ICStorageElement element; - Iterator extIterator = getExtMap().values().iterator(); + Iterator extIterator = getExtMap().values().iterator(); while (extIterator.hasNext()) { - CConfigExtensionReference extension[] = (CConfigExtensionReference[])extIterator.next(); + CConfigExtensionReference extension[] = extIterator.next(); for (int i = 0; i < extension.length; i++) { element = configRootElement.createChild(PROJECT_EXTENSION); element.setAttribute(PROJECT_EXTENSION_ATTR_POINT, extension[i].getExtensionPoint()); element.setAttribute(PROJECT_EXTENSION_ATTR_ID, extension[i].getID()); - CExtensionInfo info = (CExtensionInfo)fExtInfoMap.get(extension[i]); + CExtensionInfo info = fExtInfoMap.get(extension[i]); if (info != null) { Iterator attribIterator = info.getAttributes().entrySet().iterator(); while (attribIterator.hasNext()) { @@ -824,20 +838,17 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ } } } - - public void importStorage(String id, ICStorageElement el) throws CoreException{ - CStorage storage = getStorageBase(); - - storage.importStorage(id, el); + + public ICStorageElement importStorage(String id, ICStorageElement el) throws CoreException { + return getStorageBase().importStorage(id, el); } - + private void copyExtensionInfo(CConfigurationSpecSettings other){ other.reconcileExtensionSettings(true); if(other.fExtMap != null && other.fExtMap.size() != 0){ - fExtMap = (HashMap)other.fExtMap.clone(); - for(Iterator iter = fExtMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); - CConfigExtensionReference refs[] = (CConfigExtensionReference[])entry.getValue(); + fExtMap = (HashMap)other.fExtMap.clone(); + for (Map.Entry entry : fExtMap.entrySet()) { + CConfigExtensionReference refs[] = entry.getValue(); refs = (CConfigExtensionReference[])refs.clone(); for(int i = 0; i < refs.length; i++){ refs[i] = new CConfigExtensionReference(this, refs[i]); @@ -847,10 +858,8 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ } if(other.fExtInfoMap != null && other.fExtInfoMap.size() != 0){ - fExtInfoMap = (HashMap)other.fExtInfoMap.clone(); - for(Iterator iter = fExtInfoMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); - CExtensionInfo info = (CExtensionInfo)entry.getValue(); + for (Map.Entry entry : fExtInfoMap.entrySet()) { + CExtensionInfo info = entry.getValue(); info = new CExtensionInfo(info); entry.setValue(info); } @@ -898,26 +907,26 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ if(refs == null || refs.length == 0){ if(extIds == null || extIds.length == 0) return null; - return new Set[]{null, new HashSet(Arrays.asList(extIds))}; + return new Set[]{null, new HashSet(Arrays.asList(extIds))}; } else if(extIds == null || extIds.length == 0){ - Map map = createRefMap(refs); - return new Set[]{new HashSet(map.values()), null}; + Map map = createRefMap(refs); + return new Set[]{new HashSet(map.values()), null}; } - Set idSet = new HashSet(Arrays.asList(extIds)); - Set idSetCopy = new HashSet(idSet); - Map refsMap = createRefMap(refs); + Set idSet = new HashSet(Arrays.asList(extIds)); + Set idSetCopy = new HashSet(idSet); + Map refsMap = createRefMap(refs); idSet.removeAll(refsMap.keySet()); refsMap.keySet().removeAll(idSetCopy); - Set extSet = new HashSet(refsMap.values()); + Set extSet = new HashSet(refsMap.values()); return new Set[]{extSet, idSet}; } - private Map createRefMap(ICConfigExtensionReference refs[]){ - Map refsMap = new HashMap(refs.length); + private Map createRefMap(ICConfigExtensionReference refs[]){ + Map refsMap = new HashMap(refs.length); for(int i = 0; i < refs.length; i++){ refsMap.put(refs[i].getID(), refs[i]); } @@ -936,13 +945,13 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ for(Iterator iter = fExtMap.entrySet().iterator(); iter.hasNext();){ Map.Entry entry = (Map.Entry)iter.next(); ICConfigExtensionReference[] thisRefs = (ICConfigExtensionReference[])entry.getValue(); - ICConfigExtensionReference[] otherRefs = (ICConfigExtensionReference[])other.fExtMap.get(entry.getKey()); + ICConfigExtensionReference[] otherRefs = other.fExtMap.get(entry.getKey()); if(otherRefs == null) return thisRefs.length == 0; if(thisRefs.length != otherRefs.length) return false; - Map map = createRefMap(thisRefs); + Map map = createRefMap(thisRefs); map.entrySet().removeAll(createRefMap(otherRefs).entrySet()); if(map.size() != 0) return false; diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescription.java index f4f7926fe17..495da3600eb 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescription.java @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; @@ -30,7 +31,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.QualifiedName; -public class CProjectDescription implements ICProjectDescription, ICDataProxyContainer { +public class CProjectDescription implements ICProjectDescription, ICDataProxyContainer { private static final String ACTIVE_CFG = "activeConfiguration"; //$NON-NLS-1$ private static final QualifiedName ACTIVE_CFG_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, ACTIVE_CFG); private static final String SETTING_CFG = "settingConfiguration"; //$NON-NLS-1$ @@ -43,15 +44,15 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon // private String fActiveCfgId; // private ICConfigurationDescription fIndexCfg; // private String fIndexCfgId; - private IProject fProject; - private ICSettingsStorage fStorage; - private ICStorageElement fRootStorageElement; - private LinkedHashMap fCfgMap = new LinkedHashMap(); + private volatile IProject fProject; + private final ICSettingsStorage fStorage; + private final ICStorageElement fRootStorageElement; + private final HashMap fCfgMap = new LinkedHashMap(); private boolean fIsReadOnly; private boolean fIsModified; - private HashMap fPropertiesMap; + private HashMap fPropertiesMap; // private boolean fNeedsActiveCfgIdPersistence; - private boolean fIsLoadding; + private boolean fIsLoading; private boolean fIsApplying; private boolean fIsCreating; @@ -151,24 +152,25 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon } - CProjectDescription(IProject project, ICStorageElement element, boolean loadding, boolean isCreating) throws CoreException { + public CProjectDescription(IProject project, ICSettingsStorage storage, ICStorageElement element, boolean loading, boolean isCreating) throws CoreException { fProject = project; + fStorage = storage; fRootStorageElement = element; - fIsReadOnly = loadding; - fIsLoadding = loadding; + fIsReadOnly = loading; + fIsLoading = loading; fActiveCfgInfo = new CfgIdPair(ACTIVE_CFG_PROPERTY); fSettingCfgInfo = new CfgIdPair(SETTING_CFG_PROPERTY); fIsCreating = isCreating; ICStorageElement el = null; CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); - if(loadding){ - Map cfgStorMap = mngr.createCfgStorages(this); - - for(Iterator iter = cfgStorMap.values().iterator(); iter.hasNext();){ - CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache((ICStorageElement)iter.next(), this); + if(loading){ + Map cfgStorMap = mngr.createCfgStorages(this); + + for (ICStorageElement sel : cfgStorMap.values()) { + CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache(sel, this); configurationCreated(cache); } - + el = getStorage(CProjectDescriptionManager.MODULE_ID, false); } @@ -176,19 +178,19 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon (CProjectDescriptionPreferences)mngr.getProjectDescriptionWorkspacePreferences(false), false); - fPropertiesMap = new HashMap(); + fPropertiesMap = new HashMap(); } - void updateProject(IProject project){ + public void updateProject(IProject project){ fProject = project; } - - void loadDatas(){ - if(!fIsReadOnly || !fIsLoadding) + + public void loadDatas(){ + if(!fIsReadOnly || !fIsLoading) return; CSettingEntryFactory factory = new CSettingEntryFactory(); - for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ + for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)iter.next(); try { cache.loadData(factory); @@ -201,16 +203,16 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon // doneInitializing(); -// fIsLoadding = false; +// fIsLoading = false; } - boolean applyDatas(SettingsContext context){ + public boolean applyDatas(SettingsContext context){ if(!fIsReadOnly || !fIsApplying) return false; CSettingEntryFactory factory = new CSettingEntryFactory(); boolean modified = false; - for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ + for (Iterator iter = fCfgMap.values().iterator(); iter.hasNext();) { CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)iter.next(); try { if(cache.applyData(factory, context)) @@ -230,58 +232,76 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon return modified; } - void doneApplying(){ + /** + * Called when the read-only project description has / is being set + * fIsApplying => false + * setModified (false) + * set the ICSettingsStorage to readonly + */ + public void doneApplying(){ doneInitializing(); fIsApplying = false; try { - ((InternalXmlStorageElement)getRootStorageElement()).setReadOnly(true, false); + getStorageBase().setReadOnly(true, false); } catch (CoreException e1) { + CCorePlugin.log(e1); } setModified(false); } - void doneLoadding(){ + public void doneLoading(){ doneInitializing(); - fIsLoadding = false; + fIsLoading = false; } - void setLoadding(boolean loadding){ - fIsLoadding = loadding; + public void setLoading(boolean loading){ + fIsLoading = loading; } private void doneInitializing(){ - for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ - CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)iter.next(); + for (ICConfigurationDescription cfg : fCfgMap.values()) { + // FIXME How and why are we down casting to a CConfigurationDescriptionCache. Comments, please! + CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)cfg; cache.doneInitialization(); } - + if(fIsReadOnly) fPrefs.setReadOnly(true); } - public boolean isLoadding(){ - return fIsLoadding; + public boolean isLoading(){ + return fIsLoading; } public boolean isApplying(){ return fIsApplying; } - public CProjectDescription(CProjectDescription base, boolean saving, ICStorageElement el, boolean isCreating) { + /** + * Create a project description based on another project description + * + * @param base + * @param saving + * @param storage + * @param el + * @param isCreating + */ + public CProjectDescription(CProjectDescription base, boolean saving, ICSettingsStorage storage, ICStorageElement el, boolean isCreating) { fActiveCfgInfo = new CfgIdPair(base.fActiveCfgInfo); fSettingCfgInfo = new CfgIdPair(base.fSettingCfgInfo); fProject = base.fProject; + fStorage = storage; fRootStorageElement = el; fIsReadOnly = saving; - fIsLoadding = base.fIsLoadding; + fIsLoading = base.fIsLoading; fIsApplying = saving || base.fIsApplying; fIsCreating = isCreating; fPrefs = new CProjectDescriptionPreferences(base.fPrefs, (CProjectDescriptionPreferences)CProjectDescriptionManager.getInstance().getProjectDescriptionWorkspacePreferences(false), false); - for(Iterator iter = base.fCfgMap.values().iterator(); iter.hasNext();){ + for(Iterator iter = base.fCfgMap.values().iterator(); iter.hasNext();){ try { IInternalCCfgInfo cfgDes = (IInternalCCfgInfo)iter.next(); if(fIsReadOnly){ @@ -303,7 +323,29 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon } } - fPropertiesMap = (HashMap)base.fPropertiesMap.clone(); + fPropertiesMap = (HashMap)base.fPropertiesMap.clone(); + } + + /** + * Convert the current CConfigurationDescriptions to cached versions + * This occurs during the SetCProjectDescription Operation + */ + void switchToCachedConfigurationDescriptions() throws CoreException { + + for (Map.Entry e : fCfgMap.entrySet()) { + if (e.getValue() instanceof CConfigurationDescription) { + CConfigurationDescription cfgDes = (CConfigurationDescription)e.getValue(); + CConfigurationData baseData = ((IInternalCCfgInfo)cfgDes).getConfigurationData(false); + CConfigurationDescriptionCache baseCache = null; + if(baseData instanceof CConfigurationDescriptionCache){ + baseCache = (CConfigurationDescriptionCache)baseData; + baseData = baseCache.getConfigurationData(); + } + CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache(cfgDes, baseData, baseCache, + cfgDes.getSpecSettings(), this, null); + e.setValue(cache); + } + } } void configurationCreated(ICConfigurationDescription des){ @@ -325,18 +367,18 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon private String getFirstCfgId(){ if(!fCfgMap.isEmpty()){ - return (String)fCfgMap.keySet().iterator().next(); + return fCfgMap.keySet().iterator().next(); } return null; } public ICConfigurationDescription getConfigurationById(String id) { - return (ICConfigurationDescription)fCfgMap.get(id); + return fCfgMap.get(id); } public ICConfigurationDescription getConfigurationByName(String name) { - for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ - ICConfigurationDescription cfg = (ICConfigurationDescription)iter.next(); + for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ + ICConfigurationDescription cfg = iter.next(); if(name.equals(cfg.getName())) return cfg; } @@ -344,7 +386,7 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon } public ICConfigurationDescription[] getConfigurations() { - return (ICConfigurationDescription[])fCfgMap.values().toArray(new ICConfigurationDescription[fCfgMap.size()]); + return fCfgMap.values().toArray(new ICConfigurationDescription[fCfgMap.size()]); } public void removeConfiguration(String name) throws WriteAccessException { @@ -395,7 +437,11 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon public ICStorageElement getStorage(String moduleId, boolean create) throws CoreException { return getStorageBase().getStorage(moduleId, create); } - + + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException { + return getStorageBase().importStorage(id, el); + } + // public boolean containsStorage(String id) throws CoreException { // return getStorageBase().containsStorage(id); // } @@ -449,20 +495,24 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon } } - ICStorageElement getRootStorageElement() throws CoreException{ - if(fRootStorageElement == null){ - fRootStorageElement = CProjectDescriptionManager.getInstance().createStorage(fProject, true, true, isReadOnly()); - } + public ICStorageElement getRootStorageElement() throws CoreException { + if (fRootStorageElement == null) + throw ExceptionFactory.createCoreException("CProjectDescription ICStorageElement == null"); + +// if(fRootStorageElement == null){ +// fRootStorageElement = CProjectDescriptionManager.getInstance().createStorage(fProject, true, true, isReadOnly()); +// } return fRootStorageElement; } - ICStorageElement doGetCachedRootStorageElement(){ - return fRootStorageElement; - } +// ICStorageElement doGetCachedRootStorageElement(){ +// return fRootStorageElement; +// } ICSettingsStorage getStorageBase() throws CoreException{ if(fStorage == null) - fStorage = new CStorage((InternalXmlStorageElement)getRootStorageElement()); +// fStorage = new CStorage((InternalXmlStorageElement)getRootStorageElement()); + throw ExceptionFactory.createCoreException("CProjectDescription ICSettingsStorage == null"); return fStorage; } @@ -494,15 +544,14 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon if(fPrefs.isModified()) return true; - - if(fRootStorageElement != null - && ((InternalXmlStorageElement)fRootStorageElement).isDirty()) + + if(fStorage.isModified()) return true; - - for(Iterator iter = fCfgMap.values().iterator(); iter.hasNext();){ - if(((ICConfigurationDescription)iter.next()).isModified()) + + for(ICConfigurationDescription cfgDes : fCfgMap.values()) + if(cfgDes.isModified()) return true; - } + return false; } @@ -521,7 +570,16 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon } public boolean isReadOnly() { - return fIsReadOnly && !(fIsLoadding || fIsApplying); + return fIsReadOnly && !(fIsLoading || fIsApplying); + } + + public void setReadOnly(boolean readOnly, boolean keepModify) { + fIsReadOnly = readOnly; + try { + getStorageBase().setReadOnly(readOnly, keepModify); + } catch (CoreException e) { + CCorePlugin.log(e); + } } public ICSettingObject getChildSettingById(String id) { @@ -563,7 +621,7 @@ public class CProjectDescription implements ICProjectDescription, ICDataProxyCon public void removeStorage(String id) throws CoreException { getStorageBase().removeStorage(id); } - + void switchToCachedAppliedData(CProjectDescription appliedCache){ if(fIsReadOnly) return; diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionDelta.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionDelta.java index 4f779adf17d..85fdd6f819e 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionDelta.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionDelta.java @@ -17,7 +17,7 @@ import org.eclipse.cdt.core.settings.model.ICDescriptionDelta; import org.eclipse.cdt.core.settings.model.ICSettingObject; public class CProjectDescriptionDelta implements ICDescriptionDelta { - private List fChildList = new ArrayList(); + private List fChildList = new ArrayList(); private CProjectDescriptionDelta fParent; private ICSettingObject fSetting; private ICSettingObject fOldSetting; @@ -55,7 +55,7 @@ public class CProjectDescriptionDelta implements ICDescriptionDelta { } public ICDescriptionDelta[] getChildren() { - return (CProjectDescriptionDelta[])fChildList.toArray(new CProjectDescriptionDelta[fChildList.size()]); + return fChildList.toArray(new CProjectDescriptionDelta[fChildList.size()]); } public ICSettingObject getOldSetting() { diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionManager.java index 4d6c25c2063..c4aa61e0da4 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Intel Corporation and others. + * Copyright (c) 2007, 2008 Intel 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 @@ -9,10 +9,10 @@ * Intel Corporation - Initial API and implementation * Markus Schorn (Wind River Systems) * IBM Corporation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -25,6 +25,7 @@ import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -32,6 +33,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -85,14 +87,12 @@ import org.eclipse.cdt.core.settings.model.util.ListComparator; import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; import org.eclipse.cdt.core.settings.model.util.PatternNameMap; import org.eclipse.cdt.internal.core.CConfigBasedDescriptorManager; -import org.eclipse.cdt.internal.core.envvar.ContributedEnvironment; import org.eclipse.cdt.internal.core.model.CElementDelta; -import org.eclipse.cdt.internal.core.model.CModelManager; import org.eclipse.cdt.internal.core.settings.model.CExternalSettinsDeltaCalculator.ExtSettingsDelta; +import org.eclipse.cdt.internal.core.settings.model.xml.InternalXmlStorageElement; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorage; import org.eclipse.core.filesystem.EFS; -import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; -import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; @@ -126,22 +126,32 @@ import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.xml.sax.SAXException; +/** + * The CProjectDescriptionManager is to marshall the loading and storing + * of CDT Project Descriptions. + * + * This class delegates loading and store of the project model to the appropriate + * AbstractCProjectDescriptionStorage for the Project Description. [ Discovered at Project load + * time.] + * + * Users should not synchronize on the singleton instance of this class. It is the job of + * the AbstractCProjectDescriptionStorage to ensure thread safe access to the backing store + * as described in that interface. + * + * Previously this class created and persisted + * @see ICProjectDescriptionManager + */ public class CProjectDescriptionManager implements ICProjectDescriptionManager { public static final int INTERNAL_GET_IGNORE_CLOSE = 1 << 31 ; - - private static final String OLD_PROJECT_DESCRIPTION = "cdtproject"; //$NON-NLS-1$ - private static final String OLD_CDTPROJECT_FILE_NAME = ".cdtproject"; //$NON-NLS-1$ - private static final String OLD_PROJECT_OWNER_ID = "id"; //$NON-NLS-1$ - private static final String CONVERTED_CFG_NAME = "convertedConfig"; //$NON-NLS-1$ - private static final String CONVERTED_CFG_ID_PREFIX = "converted.config"; //$NON-NLS-1$ - - static final String STORAGE_FILE_NAME = ".cproject"; //$NON-NLS-1$ -// private static final QualifiedName PROJECT_DESCRCIPTION_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, "projectDescription"); //$NON-NLS-1$ - private static final String ROOT_ELEMENT_NAME = "cproject"; //$NON-NLS-1$ private static final String VERSION_ELEMENT_NAME = "fileVersion"; //$NON-NLS-1$ - public static final Version DESCRIPTION_VERSION = new Version("4.0"); //$NON-NLS-1$ - final static String MODULE_ID = "org.eclipse.cdt.core.settings"; //$NON-NLS-1$ + /** Preference Version 4.0 & 5.0 are equivalent for us. Version was inadvertently bumped + * when during project description storage work. + * This is the minimum preference version we support loading.*/ + public static final Version MIN_DESCRIPTION_VERSION = new Version("4.0"); //$NON-NLS-1$ + /** Current preference file storage version */ + public static final Version DESCRIPTION_VERSION = new Version("5.0"); //$NON-NLS-1$ + public final static String MODULE_ID = "org.eclipse.cdt.core.settings"; //$NON-NLS-1$ static final String CONFIGURATION = "cconfiguration"; //$NON-NLS-1$ private static final ICLanguageSettingEntry[] EMPTY_LANGUAGE_SETTINGS_ENTRIES_ARRAY = new ICLanguageSettingEntry[0]; private static final ICElementDelta[] EMPTY_CELEMENT_DELTA = new ICElementDelta[0]; @@ -155,15 +165,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { private static final String ROOT_PREFERENCE_ELEMENT = "preferences"; //$NON-NLS-1$ private static final String DEFAULT_CFG_ID_PREFIX = CCorePlugin.PLUGIN_ID + ".default.config"; //$NON-NLS-1$ private static final String DEFAULT_CFG_NAME = "Configuration"; //$NON-NLS-1$ - + private static final QualifiedName SCANNER_INFO_PROVIDER_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, "scannerInfoProvider"); //$NON-NLS-1$ - private static final QualifiedName LOAD_FLAG = new QualifiedName(CCorePlugin.PLUGIN_ID, "descriptionLoadded"); //$NON-NLS-1$ static class CompositeWorkspaceRunnable implements IWorkspaceRunnable { private List fRunnables = new ArrayList(); private String fName; private boolean fStopOnErr; - + CompositeWorkspaceRunnable(String name){ if(name == null) name = ""; //$NON-NLS-1$ @@ -197,89 +206,49 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { monitor.done(); } } - + public boolean isEmpty(){ return fRunnables.isEmpty(); } } - private class DesSerializationRunnable implements IWorkspaceRunnable { - private ICProjectDescription fDes; - private ICStorageElement fElement; - - public DesSerializationRunnable(ICProjectDescription des, ICStorageElement el) { - fDes = des; - fElement = el; - } + /** + * Container class for ICProjectDescription change listeners + */ + private static class ListenerDescriptor{ + final ICProjectDescriptionListener fListener; + final int fEventTypes; - public void run(IProgressMonitor monitor) throws CoreException { - serialize(fDes.getProject(), STORAGE_FILE_NAME, fElement); - ((ContributedEnvironment)CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment()).serialize(fDes); - } - - } -// private class ProjectInfoHolder{ -// CProjectDescription fDescription; -// ScannerInfoProviderProxy fSIProvider; -// } - - private class ListenerDescriptor{ - ICProjectDescriptionListener fListener; - int fEventTypes; - public ListenerDescriptor(ICProjectDescriptionListener listener, int eventTypes) { fListener = listener; fEventTypes = eventTypes; } - + public boolean handlesEvent(int eventType){ return (eventType & fEventTypes) != 0; } - } - - private static class ThreadInfo { - Map fDescriptionLoaddingMap; - Map fDescriptionApplyingMap; - Map fProjectFileSerializationMap; - - public Map getDescriptionLoaddingMap(boolean create){ - if(fDescriptionLoaddingMap == null && create){ - fDescriptionLoaddingMap = new HashMap(); - } - return fDescriptionLoaddingMap; + @Override + public int hashCode() { + return fListener.hashCode(); } - - public Map getDescriptionApplyingMap(boolean create){ - if(fDescriptionApplyingMap == null && create){ - fDescriptionApplyingMap = new HashMap(); - } - return fDescriptionApplyingMap; + @Override + public boolean equals(Object obj) { + return fListener.equals(obj); } - - public Map getProjectFileSerializationMap(boolean create){ - if(fProjectFileSerializationMap == null && create){ - fProjectFileSerializationMap = new HashMap(); - } - return fProjectFileSerializationMap; - } - } - private Map fProviderMap; - private CProjectConverterDesciptor fConverters[]; - private List fListeners = new ArrayList(); + private volatile Map fProviderMap; + private volatile CProjectConverterDesciptor fConverters[]; + /** Set of Listeners listening for Project Description Deltas */ + private Set fListeners = new CopyOnWriteArraySet(); private Map fPreferenceMap = new HashMap(); private CConfigBasedDescriptorManager fDescriptorManager; - private ThreadLocal fThreadInfo = new ThreadLocal(); - private Map fDescriptionMap = new HashMap(); //calls to this map are "manually" synchronized with the CProjectDescriptionManager object lock; private ResourceChangeHandler fRcChangeHandler; private CProjectDescriptionWorkspacePreferences fPreferences; private boolean fAllowEmptyCreatingDescription = true; // allowed by default -// private CStorage fPrefCfgStorage; private ICDataProxyContainer fPrefUpdater = new ICDataProxyContainer(){ - public void updateChild(CDataProxy child, boolean write) { if(write){ try { @@ -294,32 +263,37 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return fPreferenceMap.values().toArray(new CConfigurationDescriptionCache[fPreferenceMap.size()]); } }; - -// Map fDescriptionMap = new HashMap(); - private static CProjectDescriptionManager fInstance; - private CProjectDescriptionManager(){ - } - + /** The CProjectDescriptionManager instance */ + private static volatile CProjectDescriptionManager fInstance; + + private CProjectDescriptionManager(){} + public static CProjectDescriptionManager getInstance(){ if(fInstance == null) - fInstance = getInstanceSynch(); + synchronized(CProjectDescriptionManager.class) { + if (fInstance == null) + fInstance = new CProjectDescriptionManager(); + } return fInstance; } - - private static synchronized CProjectDescriptionManager getInstanceSynch(){ - if(fInstance == null) - fInstance = new CProjectDescriptionManager(); - return fInstance; + + public void projectClosedRemove(IProject project) { + CProjectDescriptionStorageManager.getInstance().projectClosedRemove(project); } + public void projectMove(IProject from, IProject to) { + CProjectDescriptionStorageManager.getInstance().projectMove(from, to); + } + + public Job startup(){ if(fRcChangeHandler == null){ fRcChangeHandler = new ResourceChangeHandler(); ResourcesPlugin.getWorkspace().addResourceChangeListener( - fRcChangeHandler, - IResourceChangeEvent.POST_CHANGE + fRcChangeHandler, + IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE /*| IResourceChangeEvent.POST_BUILD*/); @@ -333,7 +307,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return createPostStartupJob(); } - + private Job createPostStartupJob() { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); Job rcJob = new Job(SettingsModelMessages.getString("CProjectDescriptionManager.0")){ //$NON-NLS-1$ @@ -349,7 +323,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { IStatus.OK, CCorePlugin.PLUGIN_ID, IStatus.OK, - new String(), + "", //$NON-NLS-1$ null); } }; @@ -377,404 +351,104 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { public void shutdown(){ CExternalSettingsManager.getInstance().shutdown(); - - if(fDescriptorManager != null){ + + if(fDescriptorManager != null) { fDescriptorManager.shutdown(); + fDescriptorManager = null; } - - if(fRcChangeHandler != null){ + + if(fRcChangeHandler != null) { ResourcesPlugin.getWorkspace().removeResourceChangeListener(fRcChangeHandler); + fRcChangeHandler = null; } - } - - private ICProjectDescription getDescriptionLoadding(IProject project){ - Map map = getDescriptionLoaddingMap(false); - if(map != null) - return map.get(project); - return null; - } - - private void setDescriptionLoadding(IProject project, ICProjectDescription des){ - if(des == null){ - clearDescriptionLoadding(project); - } else { - Map map = getDescriptionLoaddingMap(true); - map.put(project, des); - } - } - - private CProjectDescription clearDescriptionLoadding(IProject project){ - Map map = getDescriptionLoaddingMap(false); - if(map != null) - return (CProjectDescription)map.remove(project); - return null; - } - - private Map getDescriptionLoaddingMap(boolean create){ - ThreadInfo info = getThreadInfo(create); - if(info != null) - return info.getDescriptionLoaddingMap(create); - return null; + + CProjectDescriptionStorageManager.getInstance().shutdown(); } - private Map getDescriptionApplyingMap(boolean create){ - ThreadInfo info = getThreadInfo(create); - if(info != null) - return info.getDescriptionApplyingMap(create); - return null; - } - - private Map getProjectFileSerializationMap(boolean create){ - ThreadInfo info = getThreadInfo(create); - if(info != null) - return info.getProjectFileSerializationMap(create); - return null; - } - - private void aboutToSaveProjectFile(IProject project){ - getProjectFileSerializationMap(true).put(project, Boolean.TRUE); - } - - private void doneSaveProjectFile(IProject project){ -// Map map = getProjectFileSerializationMap(false); -// if(map != null){ -// if(map.remove(project) != null){ -// CCorePlugin.log("incorrect .cproject file save state, ingnoring"); -// } -// } - } - - private boolean streamsMatch(InputStream stream1, InputStream stream2) throws IOException{ - do{ - int i1 = stream1.read(); - int i2 = stream2.read(); - - if(i1 != i2){ - return false; - } else if (i1 == -1){ - break; - } - }while(true); - - return true; - } - - CProjectDescription checkExternalProjectFileModification(IResource rc) throws CoreException{ - Map map = getProjectFileSerializationMap(false); - IProject project = rc.getProject(); - if(map != null){ - if(map.remove(project) != null) - return null; - } - - CProjectDescription des = (CProjectDescription)getProjectDescription(project, GET_IF_LOADDED); - if(des == null || des.isLoadding()) - return null; - - //check whether contents differ - try { - ICStorageElement oldEl = des.doGetCachedRootStorageElement(); - if(oldEl != null){ - InputStream newContents = getSharedProperty(project, STORAGE_FILE_NAME); - if (newContents != null) { - ByteArrayOutputStream oldOut = write(oldEl); - InputStream oldContents = new ByteArrayInputStream(oldOut.toByteArray()); - try { - if(streamsMatch(newContents, oldContents)) - return null; - } finally { - newContents.close(); - } - } - } - } catch (CoreException e){ - CCorePlugin.log(e); - //continue - } catch (IOException e) { - CCorePlugin.log(e); - //continue - } - - des = (CProjectDescription)loadProjectDescription(project); - des = createWritableDescription(des); - des.touch(); - - return des; - } - - private ThreadInfo getThreadInfo(boolean create){ - ThreadInfo info = fThreadInfo.get(); - if(info == null && create){ - info = new ThreadInfo(); - fThreadInfo.set(info); - } - return info; - } - - public ICProjectDescription getProjectDescription(IProject project, boolean write){ + public ICProjectDescription getProjectDescription(IProject project, boolean write) { return getProjectDescription(project, true, write); } - public ICProjectDescription getProjectDescription(IProject project, boolean load, boolean write){ + public ICProjectDescription getProjectDescription(IProject project, boolean load, boolean write) { int flags = load ? 0 : GET_IF_LOADDED; - if(write) - flags |= GET_WRITABLE; - + flags |= write ? GET_WRITABLE : 0; + return getProjectDescription(project, flags); } - public ICProjectDescription getProjectDescription(IProject project, int flags){ - - ICProjectDescription des = null; - boolean write = checkFlags(flags, GET_WRITABLE); - boolean load = !checkFlags(flags, GET_IF_LOADDED); - boolean ignoreClose = checkFlags(flags, INTERNAL_GET_IGNORE_CLOSE); - SettingsContext context = null; - - des = getDescriptionApplying(project); - - if(des == null) - des = getDescriptionLoadding(project); - - if(des == null && (ignoreClose || project.isOpen())) - des = getLoaddedDescription(project); - -// if(des == null) -// des = getDescriptionLoadding(project); - - if(des == null && load && project.isOpen()){ + public ICProjectDescription getProjectDescription(IProject project, int flags) { + AbstractCProjectDescriptionStorage storage = getProjectDescriptionStorage(project); + if (storage != null) { try { - des = loadProjectDescription(project); + return storage.getProjectDescription(flags, new NullProgressMonitor()); } catch (CoreException e) { + // FIXME Currently the resource change handler ResourceChangeHandler.getProjectDescription(...) + // Does this when the project is closed. Don't log an error or the tests will fail // CCorePlugin.log(e); } - if(des == null){ - //TODO: check if conversion needed - try { - context = new SettingsContext(project); - des = getConvertedDescription(project, context); - } catch (CoreException e) { - CCorePlugin.log(e); - } - } - - if(des != null){ - if(setLoaddedDescriptionOnLoad(project, des)){ - - if(context != null) - saveConversion(project, context, (CProjectDescription)des, new NullProgressMonitor()); - - CProjectDescriptionEvent event = createLoaddedEvent(des); - notifyListeners(event); - - des = getLoaddedDescription(project); - -// ICProjectDescription updatedDes = ExternalSettingsManager.getInstance().updateReferencedSettings(des); -// if(updatedDes != des){ -// try { -// setProjectDescription(project, updatedDes); -// } catch (CoreException e) { -// } -// } - } - } - } - - if(des != null && write){ - des = createWritableDescription((CProjectDescription)des); - } - return des; - } - - private CProjectDescription createWritableDescription(CProjectDescription cache){ - ICStorageElement el = null; - try { - el = cache.getRootStorageElement(); - el = copyElement((InternalXmlStorageElement)el, false); - } catch (CoreException e) { - CCorePlugin.log(e); - } - - CProjectDescription des = new CProjectDescription(cache, false, el, cache.isCdtProjectCreating()); - CProjectDescriptionEvent event = createCopyCreatedEvent(des, cache); - notifyListeners(event); - return des; - } - - private synchronized boolean setLoaddedDescriptionOnLoad(IProject project, ICProjectDescription des){ - des.setSessionProperty(LOAD_FLAG, Boolean.TRUE); - ICProjectDescription oldDes = getLoaddedDescription(project); - - setLoaddedDescription(project, des, true); - - if(oldDes == null) - return true; - - return oldDes.getSessionProperty(LOAD_FLAG) == null; - } - - private CProjectDescriptionEvent createLoaddedEvent(ICProjectDescription des){ - return new CProjectDescriptionEvent(CProjectDescriptionEvent.LOADED, - null, - des, - null, - null); - } - - private CProjectDescriptionEvent createCopyCreatedEvent(ICProjectDescription newDes, ICProjectDescription oldDes){ - return new CProjectDescriptionEvent(CProjectDescriptionEvent.COPY_CREATED, - null, - newDes, - oldDes, - null); - } - - CProjectDescriptionEvent createAboutToApplyEvent(ICProjectDescription newDes, ICProjectDescription oldDes){ - return new CProjectDescriptionEvent(CProjectDescriptionEvent.ABOUT_TO_APPLY, - null, - newDes, - oldDes, - null); - } - - CProjectDescriptionEvent createAppliedEvent(ICProjectDescription newDes, ICProjectDescription oldDes, ICProjectDescription appliedDes, ICDescriptionDelta delta){ - return new CProjectDescriptionEvent(CProjectDescriptionEvent.APPLIED, - delta, - newDes, - oldDes, - appliedDes); - } - - CProjectDescriptionEvent createDataAppliedEvent(ICProjectDescription newDes, ICProjectDescription oldDes, ICProjectDescription appliedDes, ICDescriptionDelta delta){ - return new CProjectDescriptionEvent(CProjectDescriptionEvent.DATA_APPLIED, - delta, - newDes, - oldDes, - appliedDes); - } - - private Object[] loadProjectDescriptionFromOldstyleStorage(IProject project) throws CoreException { - ICStorageElement rootEl = readOldCDTProjectFile(project); - if(rootEl != null){ - String ownerId = rootEl.getAttribute(OLD_PROJECT_OWNER_ID); - CProjectDescription des = (CProjectDescription)createProjectDescription(project, false); - String id = CDataUtil.genId(CONVERTED_CFG_ID_PREFIX); - des.createConvertedConfiguration(id, CONVERTED_CFG_NAME, rootEl); - return new Object[]{ownerId, des}; } return null; } - private ICProjectDescription getConvertedDescription(IProject project, SettingsContext context) throws CoreException{ - Object info[] = loadProjectDescriptionFromOldstyleStorage(project); - CProjectDescription des = null; - String ownerId; - try { - if(info != null){ - ownerId = (String)info[0]; - des = (CProjectDescription)info[1]; - setDescriptionLoadding(project, des); - des.setLoadding(true); - } else { - ownerId = null; - } - - IProjectDescription eDes = context.getEclipseProjectDescription(); - - ICProjectConverter converter = getConverter(project, ownerId, des); - if(converter != null){ - - CProjectDescription convertedDes = (CProjectDescription)converter.convertProject(project, eDes, ownerId, des); - if(convertedDes != null){ -/// ICConfigurationDescription activeCfg = convertedDes.getActiveConfiguration(); - checkHandleActiveCfgChange(convertedDes, null, eDes, new NullProgressMonitor()); - des = convertedDes; -// if(activeCfg != null){ -// checkBuildSystemChange(project, eDes, activeCfg.getBuildSystemId(), null, new NullProgressMonitor()); -// // if(convertedDes != null) -// des = convertedDes; -// } - } - } else { -// des; - } - - if(des != null && des.isValid()){ - //TODO: should be set via the CModel operation? - InternalXmlStorageElement el = null; - context.setEclipseProjectDescription(eDes); - - try { - el = copyElement((InternalXmlStorageElement)des.getRootStorageElement(), false); - } catch (CoreException e2) { - } - - des = new CProjectDescription(des, true, el, des.isCdtProjectCreating()); - try { - setDescriptionApplying(project, des); - des.applyDatas(context); - des.doneApplying(); - } finally { - clearDescriptionApplying(project); - } - } - }finally{ - CProjectDescription d = clearDescriptionLoadding(project); - if(d != null) - d.setLoadding(false); - if(des != null) - des.setLoadding(false); - } - return des; + /** + * Run the workspace modification in the current thread using the workspace scheduling rule + * Equivalent to: runWspModification(IWorkspaceRunnable, ResourcecPlugin.getWorkspace().getRoot(), IProgressMonitor) + *

+ * Note that if the workspace is locked, or the current job / thread doesn't contain the workspace + * scheduling rule, then we schedule a job to run the {@link IWorkspaceRunnable} + *

+ * The scheduled job is returned, or null if the operation was run immediately. + * + * @param runnable the IWorkspaceRunnable to run + * @param monitor + * @return scheduled job or null if the operation was run immediately + */ + public static Job runWspModification(final IWorkspaceRunnable runnable, IProgressMonitor monitor) { + return runWspModification(runnable, ResourcesPlugin.getWorkspace().getRoot(), monitor); } - - private void saveConversion(final IProject proj, - final SettingsContext context, - CProjectDescription des, - IProgressMonitor monitor) { - - - try { - context.addWorkspaceRunnable(createDesSerializationRunnable(des)); - } catch (CoreException e1) { - CCorePlugin.log(e1); - } - IWorkspaceRunnable toRun = context.createOperationRunnable(); - if(toRun != null) - runWspModification(toRun, monitor); - } - - public Job runWspModification(final IWorkspaceRunnable runnable, IProgressMonitor monitor){ + /** + * Either runs the modification in the current thread (if the workspace is not locked) + * or schedules a runnable to perform the operation + * @param runnable + * @param monitor + * @return scheduled job or null if the operation was run immediately + */ + public static Job runWspModification(final IWorkspaceRunnable runnable, final ISchedulingRule rule, IProgressMonitor monitor){ if(monitor == null) monitor = new NullProgressMonitor(); - - final IWorkspace wsp = ResourcesPlugin.getWorkspace(); - boolean scheduleRule = true; - if(!wsp.isTreeLocked()) { - ISchedulingRule rule = wsp.getRoot(); + + // Should the rule be scheduled, or run immediately + boolean scheduleRule = ResourcesPlugin.getWorkspace().isTreeLocked(); + + // Check whether current job contains rule 'rule' + // If not, we must schedule another job to execute the runnable + if (!scheduleRule) { + Job currentJob = Job.getJobManager().currentJob(); + if (currentJob != null && currentJob.getRule() != null && !currentJob.getRule().contains(rule)) + scheduleRule = true; + } + + if(!scheduleRule) { + // Run immediately IJobManager mngr = Job.getJobManager(); try{ mngr.beginRule(rule, monitor); - scheduleRule = false; - - runAtomic(runnable, monitor); - } catch (CoreException e) { - CCorePlugin.log(e); + runAtomic(runnable, rule, monitor); } catch (Exception e) { + CCorePlugin.log(e); } finally { if(!scheduleRule) monitor.done(); mngr.endRule(rule); } - } - - if(scheduleRule){ + } else { + // schedule a job for it Job job = new Job(SettingsModelMessages.getString("CProjectDescriptionManager.12")){ //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { try { - runAtomic(runnable, monitor); + runAtomic(runnable, rule, monitor); } catch (CoreException e) { CCorePlugin.log(e); return e.getStatus(); @@ -784,51 +458,33 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return Status.OK_STATUS; } }; - - job.setRule(wsp.getRoot()); + + job.setRule(rule); job.setSystem(true); job.schedule(); return job; } return null; } - - private void runAtomic(final IWorkspaceRunnable r, IProgressMonitor monitor) throws CoreException{ + + private static void runAtomic(final IWorkspaceRunnable r, ISchedulingRule rule, IProgressMonitor monitor) throws CoreException{ IWorkspace wsp = ResourcesPlugin.getWorkspace(); - -// try { - wsp.run(new IWorkspaceRunnable(){ - - public void run(IProgressMonitor monitor) throws CoreException { - try { - r.run(monitor); - } catch (Exception e){ - CCorePlugin.log(e); -// throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, e.getMessage(), e)); - } + wsp.run(new IWorkspaceRunnable(){ + public void run(IProgressMonitor monitor) throws CoreException { + try { + r.run(monitor); + } catch (Exception e){ + CCorePlugin.log(e); + throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, e.getMessage(), e)); } - - }, wsp.getRoot(), IWorkspace.AVOID_UPDATE, monitor); -// } catch (CoreException e){ -// IStatus status = e.getStatus(); -// if(!CCorePlugin.PLUGIN_ID.equals(status.getPlugin())){ -// throw e; -// } -//// Throwable t = status.getException(); -//// if(t instanceof Exception){ -//// r.handleException((Exception)t); -//// return; -//// } -//// } -// -// throw e; -// } + } + }, rule, IWorkspace.AVOID_UPDATE, monitor); } - + public void updateProjectDescriptions(IProject[] projects, IProgressMonitor monitor) throws CoreException{ if(monitor == null) monitor = new NullProgressMonitor(); - + try { IWorkspace wsp = ResourcesPlugin.getWorkspace(); if(projects == null) @@ -840,15 +496,15 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { if(des != null) dess[num++] = des; } - + if(num != 0){ final int[] fi = new int[1]; fi[0] = num; runWspModification(new IWorkspaceRunnable(){ - + public void run(IProgressMonitor monitor) throws CoreException { monitor.beginTask(SettingsModelMessages.getString("CProjectDescriptionManager.13"), fi[0]); //$NON-NLS-1$ - + for(int i = 0; i < dess.length; i++){ ICProjectDescription des = dess[i]; if(des == null) @@ -864,15 +520,15 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } }, monitor); - + } } finally { monitor.done(); } } - - private ICProjectConverter getConverter(IProject project, String oldOwnerId, ICProjectDescription des){ + + public ICProjectConverter getConverter(IProject project, String oldOwnerId, ICProjectDescription des){ CProjectConverterDesciptor[] converterDess = getConverterDescriptors(); ICProjectConverter converter = null; for(int i = 0; i < converterDess.length; i++){ @@ -887,75 +543,47 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return converter; } - + private CProjectConverterDesciptor[] getConverterDescriptors(){ if(fConverters == null){ initConverterInfoSynch(); } return fConverters; } - + private synchronized void initConverterInfoSynch(){ if(fConverters != null) return; - + IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(CProjectConverterDesciptor.PROJECT_CONVERTER_EXTPOINT_ID); IExtension exts[] = extensionPoint.getExtensions(); CProjectConverterDesciptor[] dess = new CProjectConverterDesciptor[exts.length]; - + for(int i = 0; i < exts.length; i++){ dess[i] = new CProjectConverterDesciptor(exts[i]); } - + fConverters = dess; } - public ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists) throws CoreException{ return createProjectDescription(project, loadIfExists, false); } - + public ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists, boolean creating) throws CoreException{ - ICProjectDescription des = getProjectDescription(project, loadIfExists, true); - if(des == null || !loadIfExists){ - if(creating && des != null) - creating = des.isCdtProjectCreating(); - ICStorageElement element = createStorage(project, false, true, false); - des = new CProjectDescription(project, element, false, creating); - } - return des; + int flags = ICProjectDescriptionManager.GET_WRITABLE | ICProjectDescriptionManager.GET_CREATE_DESCRIPTION; + flags |= loadIfExists ? 0 : ICProjectDescriptionManager.GET_EMPTY_PROJECT_DESCRIPTION; + flags |= creating ? ICProjectDescriptionManager.PROJECT_CREATING : 0; + + return getProjectDescription(project, flags); } - - public synchronized ICProjectDescription getLoaddedDescription(IProject project){ - CProjectDescription des = (CProjectDescription)fDescriptionMap.get(project); - if(des != null) - des.updateProject(project); - - return des; -//// try { -// ProjectInfoHolder holder = getInfoHolder(project); -// if(holder != null){ -// CProjectDescription des = holder.fDescription; -// if(des != null) -// des.updateProject(project); -// return des; -// } -//// } catch (CoreException e) { -//// } -// return null; - } - -// synchronized private ProjectInfoHolder getInfoHolder(final IProject project){ -// return (ProjectInfoHolder)fProjectInfoMap.get(project); -//// return (ProjectInfoHolder)project.getSessionProperty(PROJECT_DESCRCIPTION_PROPERTY); -// } - - public synchronized ScannerInfoProviderProxy getScannerInfoProviderProxy(IProject project){ + + public ScannerInfoProviderProxy getScannerInfoProviderProxy(IProject project){ ICProjectDescription des = getProjectDescription(project, false); if(des == null){ return new ScannerInfoProviderProxy(project); } - + ScannerInfoProviderProxy provider = (ScannerInfoProviderProxy)des.getSessionProperty(SCANNER_INFO_PROVIDER_PROPERTY); if(provider == null){ provider = new ScannerInfoProviderProxy(project); @@ -966,113 +594,26 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return provider; } - -// synchronized void setInfoHolder(final IProject project, final ProjectInfoHolder holder){ -// if(holder != null) -// fProjectInfoMap.put(project, holder); -// else -// fProjectInfoMap.remove(project); -//// try { -//// project.setSessionProperty(PROJECT_DESCRCIPTION_PROPERTY, holder); -//// } catch (CoreException e){ -//// CCorePlugin.log(e); -//// //TODO: externalize -//// final ProjectInfoHolder f = holder; -//// Job setDesJob = new Job("Set loadded description job"){ //$NON-NLS-1$ -//// protected IStatus run(IProgressMonitor monitor){ -//// try { -//// project.setSessionProperty(PROJECT_DESCRCIPTION_PROPERTY, f); -//// } catch (CoreException e) { -//// return e.getStatus(); -//// } -//// return Status.OK_STATUS; -//// } -//// }; -//// -//// setDesJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); -//// setDesJob.setPriority(Job.INTERACTIVE); -//// setDesJob.setSystem(true); -//// setDesJob.schedule(); -//// } -// } - - synchronized boolean setLoaddedDescription(final IProject project, ICProjectDescription des, boolean overwriteIfExists){ - if(!overwriteIfExists && fDescriptionMap.get(project) != null) - return false; - - if(des != null){ - if(project.exists() && project.isOpen()){ - fDescriptionMap.put(project, des); - } else { - CCorePlugin.log(SettingsModelMessages.getString("CProjectDescriptionManager.16")); //$NON-NLS-1$ - } - }else { - fDescriptionMap.remove(project); - } - - return true; -//// try { -// ProjectInfoHolder holder = getInfoHolder(project); -// boolean needSet = false; -// if(holder == null){ -// holder = new ProjectInfoHolder(); -// needSet = true; -// } -// -// boolean shouldOverwrite = overwriteIfExists || holder.fDescription == null; -// if(shouldOverwrite){ -// holder.fDescription = (CProjectDescription)des; -// if(needSet){ -// setInfoHolder(project, holder); -// } -// } -// return shouldOverwrite; -//// } catch (CoreException e) { -//// } -//// return false; - } - - private ICProjectDescription loadProjectDescription(IProject project) throws CoreException{ - ICStorageElement storage = CProjectDescriptionManager.getInstance().createStorage(project, true, false, false); - CProjectDescription des = new CProjectDescription(project, storage, true, false); - try { - setDescriptionLoadding(project, des); - des.loadDatas(); - des.doneLoadding(); - }finally{ - clearDescriptionLoadding(project); - } - return des; - } public ICProjectDescription getProjectDescription(IProject project){ return getProjectDescription(project, true); } - -// private void storeActiveCfgId(IProject project, String id){ -// try { -// project.setPersistentProperty(ACTIVE_CFG_PROPERTY, id); -// } catch (CoreException e) { -// // Hitting this error just means the default config is not set -// CCorePlugin.log(e); -// } -// } /* - * returns true if the project description was modiofied false - otherwise + * returns true if the project description was modified false - otherwise */ - boolean checkHandleActiveCfgChange(CProjectDescription newDes, CProjectDescription oldDes, IProjectDescription eDes, IProgressMonitor monitor){ + public boolean checkHandleActiveCfgChange(CProjectDescription newDes, ICProjectDescription oldDes, IProjectDescription eDes, IProgressMonitor monitor){ if(newDes == null) return false; ICConfigurationDescription newCfg = newDes.getActiveConfiguration(); if(newCfg == null) return false; - + ICConfigurationDescription oldCfg = oldDes != null ? oldDes.getActiveConfiguration() : null; checkActiveCfgChange(newDes, oldDes); checkSettingCfgChange(newDes, oldDes); - + boolean modified = false; try { @@ -1081,17 +622,17 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } catch (CoreException e) { CCorePlugin.log(e); } - + try { if(checkProjectRefChange(eDes, newCfg, oldCfg, monitor)) modified = true; } catch (CoreException e) { CCorePlugin.log(e); } - + return modified; } - + // String loadActiveCfgId(ICProjectDescription des){ // try { // return des.getProject().getPersistentProperty(ACTIVE_CFG_PROPERTY); @@ -1100,30 +641,28 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // } // return null; // } - - private Set projSetFromProjNameSet(Set projNameSet){ - if(projNameSet.size() == 0) + + private Collection projSetFromProjNameSet(Collection projNames){ + if(projNames.size() == 0) return new HashSet(0); - + Set set = new HashSet(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - - for(Iterator iter = projNameSet.iterator(); iter.hasNext();){ - IProject proj = root.getProject(iter.next()); - set.add(proj); - } - + + for (String sproj : projNames) + set.add(root.getProject(sproj)); + return set; } private boolean checkProjectRefChange(IProjectDescription des, ICConfigurationDescription newCfg, ICConfigurationDescription oldCfg, IProgressMonitor monitor) throws CoreException{ if(newCfg == null) return false; - + Map oldMap = oldCfg != null ? oldCfg.getReferenceInfo() : null; Map newMap = newCfg.getReferenceInfo(); - Set oldProjSet = oldMap != null ? projSetFromProjNameSet(oldMap.keySet()) : new HashSet(0); - Set newProjSet = newMap != null ? projSetFromProjNameSet(newMap.keySet()) : new HashSet(0); + Collection oldProjSet = oldMap != null ? projSetFromProjNameSet(oldMap.keySet()) : new HashSet(0); + Collection newProjSet = newMap != null ? projSetFromProjNameSet(newMap.keySet()) : new HashSet(0); Set tmp = new HashSet(newProjSet); newProjSet.removeAll(oldProjSet); @@ -1143,222 +682,138 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // private void checkBuildSystemChange(IProject project, String newBsId, String oldBsId, IProgressMonitor monitor) throws CoreException{ // checkBuildSystemChange(project, null, newBsId, oldBsId, monitor); // } - + private boolean checkActiveCfgChange(CProjectDescription des, - CProjectDescription oldDes -// ICConfigurationDescription newCfg, + ICProjectDescription oldDes +// ICConfigurationDescription newCfg, // ICConfigurationDescription oldCfg ){ ICConfigurationDescription oldCfg = oldDes != null ? oldDes.getActiveConfiguration() : null; // String newId = newCfg.getId(); String oldId = oldCfg != null ? oldCfg.getId() : null; - - + + return des.checkPersistActiveCfg(oldId, false); } private boolean checkSettingCfgChange(CProjectDescription des, - CProjectDescription oldDes -// ICConfigurationDescription newCfg, + ICProjectDescription oldDes +// ICConfigurationDescription newCfg, // ICConfigurationDescription oldCfg ){ ICConfigurationDescription oldCfg = oldDes != null ? oldDes.getDefaultSettingConfiguration() : null; // String newId = newCfg.getId(); String oldId = oldCfg != null ? oldCfg.getId() : null; - - + + return des.checkPersistSettingCfg(oldId, false); } - private boolean checkBuildSystemChange(IProjectDescription des, - ICConfigurationDescription newCfg, - ICConfigurationDescription oldCfg, + private boolean checkBuildSystemChange(IProjectDescription des, + ICConfigurationDescription newCfg, + ICConfigurationDescription oldCfg, IProgressMonitor monitor) throws CoreException{ String newBsId = newCfg != null ? newCfg.getBuildSystemId() : null; String oldBsId = oldCfg != null ? oldCfg.getBuildSystemId() : null; CConfigurationDataProviderDescriptor newDr = newBsId != null ? getCfgProviderDescriptor(newBsId) : null; CConfigurationDataProviderDescriptor oldDr = oldBsId != null ? getCfgProviderDescriptor(oldBsId) : null; - + String newNatures[] = newDr != null ? newDr.getNatureIds() : new String[0]; String oldNatures[] = oldDr != null ? oldDr.getNatureIds() : new String[0]; String conflictingNatures[] = newDr != null ? newDr.getConflictingNatureIds() : new String[0]; String natureIds[] = des.getNatureIds(); - + Set curSet = new HashSet(Arrays.asList(natureIds)); // Set newSet = new HashSet(Arrays.asList(newNatures)); // Set oldSet = new HashSet(Arrays.asList(oldNatures)); HashSet newCurSet = new HashSet(curSet); // newSet.removeAll(oldSet); // oldSet.removeAll(tmp); - + newCurSet.removeAll(Arrays.asList(oldNatures)); newCurSet.addAll(Arrays.asList(newNatures)); newCurSet.removeAll(Arrays.asList(conflictingNatures)); - + if(!newCurSet.equals(curSet)){ des.setNatureIds(newCurSet.toArray(new String[newCurSet.size()])); return true; } - + return false; - - - - } public void setProjectDescription(IProject project, ICProjectDescription des) throws CoreException { setProjectDescription(project, des, false, null); } - + public void setProjectDescription(IProject project, ICProjectDescription des, boolean force, IProgressMonitor monitor) throws CoreException { - int flags = 0; - if(force) - flags |= SET_FORCE; + int flags = force ? SET_FORCE : 0; setProjectDescription(project, des, flags, monitor); } - + static boolean checkFlags(int flags, int check){ return (flags & check) == check; } - + + /** ThreadLocal flag to let CDescriptor know whether already in a setProjectDescription */ + ThreadLocal settingProjectDescription = new ThreadLocal(){@Override protected Boolean initialValue() {return false;}}; public void setProjectDescription(IProject project, ICProjectDescription des, int flags, IProgressMonitor monitor) throws CoreException { - - if(des != null){ - if(!des.isValid() && (!fAllowEmptyCreatingDescription || !des.isCdtProjectCreating())) - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.17") + project.getName()); //$NON-NLS-1$ - - if(!checkFlags(flags, SET_FORCE) && !des.isModified()) - return; - - if(((CProjectDescription)des).isLoadding()){ - //do nothing - // throw ExceptionFactory.createCoreException("description is being loadded"); - return; - } - - if(((CProjectDescription)des).isApplying()){ - //do nothing - // throw ExceptionFactory.createCoreException("description is being applied"); - return; - } - } - - if(monitor == null) - monitor = new NullProgressMonitor(); - - CModelManager manager = CModelManager.getDefault(); - ICProject cproject = manager.create(project); - - SetCProjectDescriptionOperation op = new SetCProjectDescriptionOperation(cproject, (CProjectDescription)des, flags); try { - op.runOperation(monitor); - } catch (IllegalArgumentException e){ - throw ExceptionFactory.createCoreException(e); + settingProjectDescription.set(true); + if(des != null){ + if (!project.isAccessible()) + throw ExceptionFactory.createCoreException(MessageFormat.format(CCorePlugin.getResourceString("ProjectDescription.ProjectNotAccessible"), project.getName())); //$NON-NLS-1$ + + if(!des.isValid() && (!fAllowEmptyCreatingDescription || !des.isCdtProjectCreating())) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.17") + project.getName()); //$NON-NLS-1$ + + if(!checkFlags(flags, SET_FORCE) && !des.isModified()) + return; + + if(((CProjectDescription)des).isLoading()){ + throw ExceptionFactory.createCoreException("description is being loadded"); //$NON-NLS-1$ + } + + if(((CProjectDescription)des).isApplying()){ + throw ExceptionFactory.createCoreException("description is being applied"); //$NON-NLS-1$ + } + } + CProjectDescriptionStorageManager.getInstance().setProjectDescription(project, des, flags, monitor); + } finally { + settingProjectDescription.set(false); } } - - IWorkspaceRunnable createDesSerializationRunnable(CProjectDescription des) throws CoreException{ - final ICStorageElement element = des.getRootStorageElement(); - - IWorkspaceRunnable r = new DesSerializationRunnable(des, element); - return r; - } - -// void reconsileBinaryParserSettings(ICConfigurationDescription cfgDes, boolean toExtensionRefs){ -// reconsileBinaryParserExtRefs(cfgDes, null, toExtensionRefs); -// } -// -// void reconsileErrorParserSettings(ICConfigurationDescription cfgDes, boolean toExtensionRefs){ -// reconsileErrorParserExtRefs(cfgDes, null, toExtensionRefs); -// } -// -// boolean reconsileBinaryParserExtRefs(ICConfigurationDescription cfgDes, ICConfigExtensionReference refs[], boolean toExtensionRefs){ -// ICTargetPlatformSetting tp = cfgDes.getTargetPlatformSetting(); -// if(tp != null){ -// if(toExtensionRefs){ -// String ids[] = tp.getBinaryParserIds(); -// if(ids != null){ -// return reconsileExtensionReferences(cfgDes, CCorePlugin.BINARY_PARSER_UNIQ_ID, refs, ids); -// } -// } else { -// String ids[] = getIds(cfgDes, refs, CCorePlugin.BINARY_PARSER_UNIQ_ID); -// tp.setBinaryParserIds(ids); -// } -// -// } -// return false; -// } -// -// boolean reconsileErrorParserExtRefs(ICConfigurationDescription cfgDes, ICConfigExtensionReference refs[], boolean toExtensionRefs){ -// ICBuildSetting bs = cfgDes.getBuildSetting(); -// if(bs != null){ -// if(toExtensionRefs){ -// String ids[] = bs.getErrorParserIDs(); -// if(ids != null){ -// return reconsileExtensionReferences(cfgDes, CCorePlugin.ERROR_PARSER_UNIQ_ID, refs, ids); //$NON-NLS-1$ -// } -// } else { -// String ids[] = getIds(cfgDes, refs, CCorePlugin.ERROR_PARSER_UNIQ_ID); -// bs.setErrorParserIDs(ids); -// } -// -// } -// -// return false; -// } -// -// private String[] getIds(ICConfigurationDescription des, ICConfigExtensionReference refs[], String extPointId){ -// return getIds(refs != null ? refs : des.get(extPointId)); -// } -// -// private String[] getIds(ICConfigExtensionReference refs[]){ -// String[] ids = new String[refs.length]; -// for(int i = 0; i < refs.length; i++){ -// ids[i] = refs[i].getID(); -// } -// return ids; -// } -// -// boolean reconsileExtensionReferences(ICConfigurationDescription des, String extPointId, String[] extIds){ -// return reconsileExtensionReferences(des, extPointId, null, extIds); -// } - - void serialize(final CProjectDescription des) throws CoreException{ - IWorkspaceRunnable r = createDesSerializationRunnable(des); - runWspModification(r, new NullProgressMonitor()); - -// IWorkspace wsp = ResourcesPlugin.getWorkspace(); -// -// if(wsp.isTreeLocked()){ -// Job job = new Job("info serialization"){ -// protected IStatus run(IProgressMonitor monitor) { -// try { -// serialize(des.getProject(), STORAGE_FILE_NAME, element); -// ((ContributedEnvironment)CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment()).serialize(des); -// } catch (CoreException e) { -// return e.getStatus(); -// } -// return Status.OK_STATUS; -// } -// }; -// -// job.setRule(wsp.getRoot()); -// job.setSystem(true); -// job.schedule(); -// } else { -// serialize(des.getProject(), STORAGE_FILE_NAME, element); -// ((ContributedEnvironment)CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment()).serialize(des); -// } -// serialize(des.getProject(), STORAGE_FILE_NAME, element); + /** + * Indicates that a setProjectDescription is currently in progress to prevent recursive setProjectDescription + * @return boolean + */ + public boolean isCurrentThreadSetProjectDescription() { + return settingProjectDescription.get(); } - - private void serializePreference(String key, ICStorageElement element) throws CoreException{ - Document doc = getDocument(element); - + + private AbstractCProjectDescriptionStorage getProjectDescriptionStorage(IProject project) { + return CProjectDescriptionStorageManager.getInstance().getProjectDescriptionStorage(project); + } + + /** + * Return an ICSettingsStorage based on the provided ICStorageElement + * in the given IProject + * @param project + * @return ICSettingsStorages + */ + public ICSettingsStorage getStorageForElement(IProject project, ICStorageElement element) throws CoreException { + if (project != null) + return getProjectDescriptionStorage(project).getStorageForElement(element); + // project is null means it's a preference element, uses XmlStorages + return new XmlStorage((InternalXmlStorageElement)element); + } + + private void serializePreference(String key, InternalXmlStorageElement element) throws CoreException{ + Document doc = element.fElement.getOwnerDocument(); + // Transform the document to something we can save in a file ByteArrayOutputStream stream = new ByteArrayOutputStream(); FileOutputStream fileStream = null; @@ -1370,31 +825,31 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(stream); transformer.transform(source, result); - + // Save the document File file = getPreferenceFile(key); String utfString = stream.toString("UTF-8"); //$NON-NLS-1$ - + if (file.exists()) { -// if (projectFile.isReadOnly()) { -// +// if (projectFile.isReadOnly()) { +// // // Inform Eclipse that we are intending to modify this file // // This will provide the user the opportunity, via UI prompts, to fetch the file from source code control // // reset a read-only file protection to write etc. // // If there is no shell, i.e. shell is null, then there will be no user UI interaction -// +// // //TODO // //IStatus status = projectFile.getWorkspace().validateEdit(new IFile[]{projectFile}, shell); -// +// // // If the file is still read-only, then we should not attempt the write, since it will // // just fail - just throw an exception, to be caught below, and inform the user // // For other non-successful status, we take our chances, attempt the write, and pass // // along any exception thrown -// +// // //if (!status.isOK()) { // // if (status.getCode() == IResourceStatus.READ_ONLY_LOCAL) { // // stream.close(); -// // throw new CoreException(status); +// // throw new CoreException(status); // //} // //} // } @@ -1422,106 +877,6 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } - private ByteArrayOutputStream write(ICStorageElement element) throws CoreException { - Document doc = getDocument(element); - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - try { - Transformer transformer = TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ - DOMSource source = new DOMSource(doc); - StreamResult result = new StreamResult(stream); - transformer.transform(source, result); - - return stream; - } catch (TransformerConfigurationException e){ - throw ExceptionFactory.createCoreException(e); - } catch (TransformerException e) { - throw ExceptionFactory.createCoreException(e); - } - } - - private void serialize(IProject project, String file, ICStorageElement element) throws CoreException{ - try { - IFile projectFile = project.getFile(file); - ByteArrayOutputStream stream = write(element); - - String utfString = stream.toString("UTF-8"); //$NON-NLS-1$ - aboutToSaveProjectFile(project); - - try { - if (projectFile.exists()) { - if (projectFile.isReadOnly()) { - // Inform Eclipse that we are intending to modify this file - // This will provide the user the opportunity, via UI prompts, to fetch the file from source code control - // reset a read-only file protection to write etc. - // If there is no shell, i.e. shell is null, then there will be no user UI interaction - - //TODO - //IStatus status = projectFile.getWorkspace().validateEdit(new IFile[]{projectFile}, shell); - - // If the file is still read-only, then we should not attempt the write, since it will - // just fail - just throw an exception, to be caught below, and inform the user - // For other non-successful status, we take our chances, attempt the write, and pass - // along any exception thrown - - //if (!status.isOK()) { - // if (status.getCode() == IResourceStatus.READ_ONLY_LOCAL) { - // stream.close(); - // throw new CoreException(status); - //} - //} - } - try { - projectFile.setContents(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ - } catch (CoreException e) { - if (projectFile.getLocation().toFile().isHidden()) { - String os = System.getProperty("os.name"); //$NON-NLS-1$ - if (os != null && os.startsWith("Win")) { //$NON-NLS-1$ - projectFile.delete(true, null); - projectFile.create(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ - CCorePlugin.log(e.getLocalizedMessage() + - "\n** Error occured because of file status ." + //$NON-NLS-1$ - "\n** This status is disabled now, to allow writing."); //$NON-NLS-1$ - } else throw(e); - } else throw(e); - } - } else { - projectFile.create(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ - } - }finally{ - doneSaveProjectFile(project); - stream.close(); - } - } catch (IOException e) { - throw ExceptionFactory.createCoreException(e); - } - } - - private Document getDocument(ICStorageElement element){ - return ((InternalXmlStorageElement)element).fElement.getOwnerDocument(); - } - - Map createCfgStorages(ICProjectDescription des) throws CoreException{ - LinkedHashMap map = new LinkedHashMap(); - ICStorageElement rootElement = des.getStorage(MODULE_ID, false); - if(rootElement != null){ - ICStorageElement children[] = rootElement.getChildren(); - - for(int i = 0; i < children.length; i++){ - ICStorageElement el = children[i]; - if(CONFIGURATION.equals(el.getName())){ - String id = el.getAttribute(CConfigurationSpecSettings.ID); - if(id != null) - map.put(id, el); - } - } - } - return map; - } - ICLanguageSetting findLanguagSettingForFile(String fileName, IProject project, ICLanguageSetting settings[]){ // if(cType != null){ // setting = findLanguageSettingForContentTypeId(cType.getId(), settings, true); @@ -1547,7 +902,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return null; } - + public ICLanguageSetting[] findCompatibleSettingsForContentTypeId(String id, ICLanguageSetting[] settings/*, boolean src*/){ IContentTypeManager manager = Platform.getContentTypeManager(); IContentType cType = manager.getContentType(id); @@ -1569,9 +924,8 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { public ICLanguageSetting findLanguageSettingForExtension(String ext, ICLanguageSetting settings[]/*, boolean src*/){ ICLanguageSetting setting; - ICLanguageSetting insensitiveMatch= null; for(int i = 0; i < settings.length; i++){ - setting = settings[i]; + setting = settings[i]; String exts[] = setting.getSourceExtensions(); /* if(src){ if(setting.getSourceContentType() == null){ @@ -1582,29 +936,51 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { exts = setting.getHeaderExtensions(); } } -*/ +*/ if(exts != null && exts.length != 0){ - // try case-sensitive first for(int j = 0; j < exts.length; j++){ if(ext.equals(exts[j])) return setting; } - // no case-sensitive match, since the file types prefs are not case sensitive, don't be here - if (insensitiveMatch == null) { - for(int j = 0; j < exts.length; j++){ - if(ext.equalsIgnoreCase(exts[j])) { - insensitiveMatch= setting; - break; - } - } + } + } + return null; + } + + /** + * Returns a map of configurations elements as discovered from the supplied project + * description + * @param des + * @return Map String -> ICStorageElement: configuration name -> configuration ICStorageElement + * @throws CoreException + */ + Map createCfgStorages(ICProjectDescription des) throws CoreException{ + LinkedHashMap map = new LinkedHashMap(); + ICStorageElement rootElement = des.getStorage(MODULE_ID, false); + if(rootElement != null){ + ICStorageElement children[] = rootElement.getChildren(); + + for(int i = 0; i < children.length; i++){ + ICStorageElement el = children[i]; + if(CONFIGURATION.equals(el.getName())){ + String id = el.getAttribute(CConfigurationSpecSettings.ID); + if(id != null) + map.put(id, el); } } } - return insensitiveMatch; + return map; } - ICStorageElement createStorage(ICSettingsStorage storage, String cfgId) throws CoreException{ - ICStorageElement rootElement = storage.getStorage(MODULE_ID, true); + /** + * Create the configuration storage cfgId in the project description + * @param storage the root settingsStorage of the project + * @param cfgId the configuration Id desire + * @return the cfgId as discovered in the project description or a new ICStorageElement with that Id + * @throws CoreException on failure to create storage + */ + ICStorageElement createStorage(ICSettingsStorage storage, String cfgId) throws CoreException { + ICStorageElement rootElement = storage.getStorage(MODULE_ID, true); // throws CoreException ICStorageElement children[] = rootElement.getChildren(); ICStorageElement element = null; @@ -1615,12 +991,12 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + if(element == null){ element = rootElement.createChild(CONFIGURATION); element.setAttribute(CConfigurationSpecSettings.ID, cfgId); } - + return element; } @@ -1648,7 +1024,13 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { config.setAttribute(CConfigurationSpecSettings.ID, cfgId); return config; } - + + /** + * Remove the storage with the supplied configuration Id from the project + * @param storage The root settingsStorage of the project + * @param cfgId the configuration ID which would be + * @throws CoreException + */ void removeStorage(ICSettingsStorage storage, String cfgId) throws CoreException{ ICStorageElement rootElement = storage.getStorage(MODULE_ID, false); if(rootElement != null){ @@ -1663,19 +1045,19 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } } - + CConfigurationData loadData(ICConfigurationDescription des, IProgressMonitor monitor) throws CoreException{ if(monitor == null) monitor = new NullProgressMonitor(); - + CConfigurationDataProvider provider = getProvider(des); return provider.loadConfiguration(des, monitor); } - + CConfigurationData applyData(CConfigurationDescriptionCache des, ICConfigurationDescription baseDescription, CConfigurationData base, SettingsContext context, IProgressMonitor monitor) throws CoreException { if(monitor == null) monitor = new NullProgressMonitor(); - + CConfigurationDataProvider provider = getProvider(des); context.init(des); return provider.applyConfiguration(des, baseDescription, base, context, monitor); @@ -1696,24 +1078,24 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { void removeData(ICConfigurationDescription des, CConfigurationData data, IProgressMonitor monitor) throws CoreException{ if(monitor == null) monitor = new NullProgressMonitor(); - + CConfigurationDataProvider provider = getProvider(des); provider.removeConfiguration(des, data, monitor); } - + CConfigurationData createData(ICConfigurationDescription des, ICConfigurationDescription baseDescription, CConfigurationData base, boolean clone, IProgressMonitor monitor) throws CoreException{ if(monitor == null) monitor = new NullProgressMonitor(); - + CConfigurationDataProvider provider = getProvider(des); return provider.createConfiguration(des, baseDescription, base, clone, monitor); } - + private CConfigurationDataProvider getProvider(ICConfigurationDescription des) throws CoreException{ CConfigurationDataProviderDescriptor providerDes = getCfgProviderDescriptor(des); if(providerDes == null) throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.1")); //$NON-NLS-1$ - + return providerDes.getProvider(); } @@ -1723,33 +1105,28 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { private CConfigurationDataProviderDescriptor getCfgProviderDescriptor(String id){ initProviderInfo(); - return fProviderMap.get(id); } - - private synchronized void initProviderInfo(){ + + private void initProviderInfo(){ if(fProviderMap != null) return; - - initProviderInfoSynch(); - } - - private synchronized void initProviderInfoSynch(){ - if(fProviderMap != null) - return; - - IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(CConfigurationDataProviderDescriptor.DATA_PROVIDER_EXTPOINT_ID); - IExtension exts[] = extensionPoint.getExtensions(); - fProviderMap = new HashMap(exts.length); - - for(int i = 0; i < exts.length; i++){ - CConfigurationDataProviderDescriptor des = new CConfigurationDataProviderDescriptor(exts[i]); - fProviderMap.put(des.getId(), des); + + synchronized (this) { + if(fProviderMap != null) + return; + + IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(CConfigurationDataProviderDescriptor.DATA_PROVIDER_EXTPOINT_ID); + IExtension exts[] = extensionPoint.getExtensions(); + fProviderMap = new HashMap(exts.length); + + for(int i = 0; i < exts.length; i++){ + CConfigurationDataProviderDescriptor des = new CConfigurationDataProviderDescriptor(exts[i]); + fProviderMap.put(des.getId(), des); + } } } - - - + /* CConfigurationSpecSettings createConfigurationSpecSettings(ICConfigurationDescription cfg) throws CoreException{ CConfigurationSpecSettings settings = null; if(cfg instanceof CConfigurationDescriptionCache){ @@ -1765,33 +1142,8 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return settings; } -*/ - - private ICStorageElement readOldCDTProjectFile(IProject project) throws CoreException { - ICStorageElement storage = null; - try { - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = null; - InputStream stream = getSharedProperty(project, OLD_CDTPROJECT_FILE_NAME); - if(stream != null){ - doc = builder.parse(stream); - NodeList nodeList = doc.getElementsByTagName(OLD_PROJECT_DESCRIPTION); +*/ - if (nodeList != null && nodeList.getLength() > 0) { - Node node = nodeList.item(0); - storage = new InternalXmlStorageElement((Element)node, false); - } - } - } catch(ParserConfigurationException e){ - throw ExceptionFactory.createCoreException(e); - } catch (SAXException e) { - throw ExceptionFactory.createCoreException(e); - } catch (IOException e) { - throw ExceptionFactory.createCoreException(e); - } - return storage; - } - public ICStorageElement createPreferenceStorage(String key, boolean createEmptyIfNotFound, boolean readOnly) throws CoreException{ try { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); @@ -1803,21 +1155,22 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { stream = getPreferenceProperty(key); if(stream != null){ doc = builder.parse(stream); - + // Get the first element in the project file Node rootElement = doc.getFirstChild(); - + if (rootElement.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE) { throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.2")); //$NON-NLS-1$ } else { - // Make sure that the version is compatible with the manager String fileVersion = rootElement.getNodeValue(); Version version = new Version(fileVersion); - if (DESCRIPTION_VERSION.compareTo(version) != 0) { + // Make sure that the version is compatible with the manager + // Version must between min version and current version inclusive + if (MIN_DESCRIPTION_VERSION.compareTo(version) > 0 || DESCRIPTION_VERSION.compareTo(version) < 0) { throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.3")); //$NON-NLS-1$ } } - + // Now get the project root element (there should be only one) NodeList nodes = doc.getElementsByTagName(ROOT_PREFERENCE_ELEMENT); if (nodes.getLength() == 0) @@ -1846,12 +1199,12 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } } - + if(element == null) { doc = builder.newDocument(); ProcessingInstruction instruction = doc.createProcessingInstruction(VERSION_ELEMENT_NAME, DESCRIPTION_VERSION.toString()); doc.appendChild(instruction); - element = doc.createElement(ROOT_PREFERENCE_ELEMENT); + element = doc.createElement(ROOT_PREFERENCE_ELEMENT); doc.appendChild(element); } return new InternalXmlStorageElement(element, null, false, readOnly); @@ -1859,7 +1212,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { throw ExceptionFactory.createCoreException(e); } } - + private InputStream getPreferenceProperty(String key) { InputStream stream = null; File file = getPreferenceFile(key); @@ -1872,85 +1225,13 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return stream; } - + private File getPreferenceFile(String key){ IPath path = CCorePlugin.getDefault().getStateLocation(); path = path.append(key); return path.toFile(); } - - - ICStorageElement createStorage(IProject project, boolean reCreate, boolean createEmptyIfNotFound, boolean readOnly) throws CoreException{ - try { - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = null; - Element element = null; - InputStream stream = null; - if(reCreate){ - try{ - stream = getSharedProperty(project, STORAGE_FILE_NAME); - if(stream != null){ - doc = builder.parse(stream); - - // Get the first element in the project file - Node rootElement = doc.getFirstChild(); - - if (rootElement.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE) { - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.7")); //$NON-NLS-1$ - } else { - // Make sure that the version is compatible with the manager - String fileVersion = rootElement.getNodeValue(); - Version version = new Version(fileVersion); - if (DESCRIPTION_VERSION.compareTo(version) != 0) { - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.8")); //$NON-NLS-1$ - } - } - - // Now get the project root element (there should be only one) - NodeList nodes = doc.getElementsByTagName(ROOT_ELEMENT_NAME); - if (nodes.getLength() == 0) - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.9")); //$NON-NLS-1$ - Node node = nodes.item(0); - if(node.getNodeType() != Node.ELEMENT_NODE) - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.10")); //$NON-NLS-1$ - element = (Element)node; - } else if(!createEmptyIfNotFound){ - throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.11")); //$NON-NLS-1$ - } - } catch (FactoryConfigurationError e) { - if(!createEmptyIfNotFound) - throw ExceptionFactory.createCoreException(e.getLocalizedMessage()); - } catch (SAXException e) { - if(!createEmptyIfNotFound) - throw ExceptionFactory.createCoreException(e); - } catch (IOException e) { - if(!createEmptyIfNotFound) - throw ExceptionFactory.createCoreException(e); - } finally { - if(stream != null){ - try { - stream.close(); - } catch (IOException e) { - } - } - } - } - - if(element == null) { - doc = builder.newDocument(); - ProcessingInstruction instruction = doc.createProcessingInstruction(VERSION_ELEMENT_NAME, DESCRIPTION_VERSION.toString()); - doc.appendChild(instruction); - element = doc.createElement(ROOT_ELEMENT_NAME); - doc.appendChild(element); - } - - return new InternalXmlStorageElement(element, null, false, readOnly); - } catch (ParserConfigurationException e) { - throw ExceptionFactory.createCoreException(e); - } - } - - + public static File toLocalFile(URI uri, IProgressMonitor monitor) throws CoreException { IFileStore fileStore = EFS.getStore(uri); File localFile = fileStore.toLocalFile(EFS.NONE, monitor); @@ -1959,73 +1240,10 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { localFile= fileStore.toLocalFile(EFS.CACHE, monitor); return localFile; } - - public InputStream getSharedProperty(IProject project, String key) throws CoreException { - InputStream stream = null; - final IFile rscFile = project.getFile(key); - if (rscFile.exists()) { - try { - stream = rscFile.getContents(); - } catch (CoreException e){ - //try refreshing - final Throwable[] t = new Throwable[1]; - Job job = runWspModification(new IWorkspaceRunnable(){ - - public void run(IProgressMonitor monitor) throws CoreException { - try { - rscFile.refreshLocal(IResource.DEPTH_ZERO, null); - } catch (Exception e){ - t[0] = e; - } - } - - }, new NullProgressMonitor()); - - //if refresh was performed "inline" without job scheduled - if(job == null){ - //if no exceptions occured - if(t[0] == null) { - //try get contents - stream = rscFile.getContents(); - } else { - //refresh failed - if(t[0] instanceof CoreException) - throw (CoreException)t[0]; - throw e; - } - } else { - throw e; - } - } - } else { - // when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible - // so default to using java.io.File - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258 - URI location = rscFile.getLocationURI(); - if (location != null) { - IFileStore file = EFS.getStore(location); - IFileInfo info = null; - - if(file != null) { - info = file.fetchInfo(); - if (info != null && info.exists()) { - stream = file.openInputStream(EFS.NONE, null); - } - } - } - } - return stream; - } - -/* public IScannerInfoProvider getScannerInfoProvider(IProject project){ - - return ScannerProvider.getInstance(); - } -*/ ICDescriptionDelta createDelta(ICProjectDescription newDescription, ICProjectDescription oldDescription){ CProjectDescriptionDelta delta = new CProjectDescriptionDelta(newDescription, oldDescription); - + if(delta.getDeltaKind() == ICDescriptionDelta.CHANGED){ ICConfigurationDescription[] cfgs = newDescription.getConfigurations(); for(int i = 0; i < cfgs.length; i++){ @@ -2035,29 +1253,29 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { delta.addChild(cfgDelta); } } - + cfgs = oldDescription.getConfigurations(); for(int i = 0; i < cfgs.length; i++){ ICConfigurationDescription newCfg = newDescription.getConfigurationById(cfgs[i].getId()); if(newCfg == null) delta.addChild(createDelta(null, cfgs[i])); } - + if(checkCfgChange(newDescription, oldDescription, true)) delta.addChangeFlags(ICDescriptionDelta.ACTIVE_CFG); if(checkCfgChange(newDescription, oldDescription, false)) delta.addChangeFlags(ICDescriptionDelta.INDEX_CFG); - + if(oldDescription.isCdtProjectCreating() && !newDescription.isCdtProjectCreating()) delta.addChangeFlags(ICDescriptionDelta.PROJECT_CREAION_COMPLETED); } return delta.isEmpty() ? null : delta; } - + private boolean checkCfgChange(ICProjectDescription newDes, ICProjectDescription oldDes, boolean active){ ICConfigurationDescription newCfg, oldCfg; - + if(active){ newCfg = newDes.getActiveConfiguration(); oldCfg = oldDes.getActiveConfiguration(); @@ -2065,19 +1283,19 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { newCfg = newDes.getDefaultSettingConfiguration(); oldCfg = oldDes.getDefaultSettingConfiguration(); } - + if(newCfg == null){ return oldCfg != null; } else if (oldCfg == null){ return true; - } + } return !newCfg.getId().equals(oldCfg.getId()); } - + /* void postProcessNewDescriptionCache(CProjectDescription des, ICProjectDescriptionDelta delta){ if(delta == null && delta.getDeltaKind() != ICProjectDescriptionDelta.CHANGED) return; - + ICConfigurationDescription indexCfg = des.getIndexConfiguration(); ICConfigurationDescription activeCfg = des.getActiveConfiguration(); ICProjectDescriptionDelta activeCfgDelta = findDelta(activeCfg.getId(), delta); @@ -2087,10 +1305,10 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { des.setIndexConfiguration(activeCfg); } } - - + + } -*/ +*/ private ICDescriptionDelta findDelta(String id, ICDescriptionDelta delta){ ICDescriptionDelta children[] = delta.getChildren(); ICSettingObject obj; @@ -2101,7 +1319,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return null; } - + public int calculateDescriptorFlags(ICConfigurationDescription newCfg, ICConfigurationDescription oldCfg){ try { int flags = 0; @@ -2111,25 +1329,25 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { String oldId = oldSettings.getCOwnerId(); if(!CDataUtil.objectsEqual(newId, oldId)) flags |= ICDescriptionDelta.OWNER; - - Map newMap = newSettings.getExtensionMapCopy(); - Map oldMap = oldSettings.getExtensionMapCopy(); - - for(Iterator iter = newMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); + + Map newMap = newSettings.getExtensionMapCopy(); + Map oldMap = oldSettings.getExtensionMapCopy(); + + for(Iterator> iter = newMap.entrySet().iterator(); iter.hasNext();){ + Map.Entry entry = iter.next(); iter.remove(); - CConfigExtensionReference[] oldRefs = (CConfigExtensionReference[])oldMap.remove(entry.getKey()); + CConfigExtensionReference[] oldRefs = oldMap.remove(entry.getKey()); if(oldRefs == null){ flags |= ICDescriptionDelta.EXT_REF; break; } - + CConfigExtensionReference[] newRefs = (CConfigExtensionReference[])entry.getValue(); if(newRefs.length != oldRefs.length){ flags |= ICDescriptionDelta.EXT_REF; break; } - + Set newSet = new HashSet(Arrays.asList(newRefs)); Set oldSet = new HashSet(Arrays.asList(oldRefs)); if(newSet.size() != oldSet.size()){ @@ -2143,7 +1361,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + return flags; } catch (CoreException e) { CCorePlugin.log(e); @@ -2167,7 +1385,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { delta.addChild(createDelta(foDess[i], null)); } } - + foDess = oldCfg.getFolderDescriptions(); for(int i = 0; i < foDess.length; i++){ ICResourceDescription newDes = newCfg.getResourceDescription(foDess[i].getPath(), true); @@ -2187,7 +1405,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { delta.addChild(createDelta(fiDess[i], null)); } } - + fiDess = oldCfg.getFileDescriptions(); for(int i = 0; i < fiDess.length; i++){ ICResourceDescription newDes = newCfg.getResourceDescription(fiDess[i].getPath(), true); @@ -2199,14 +1417,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { CProjectDescriptionDelta tpsDelta = createDelta(newCfg.getTargetPlatformSetting(), oldCfg.getTargetPlatformSetting()); if(tpsDelta != null) delta.addChild(tpsDelta); - + if(!newCfg.getName().equals(oldCfg.getName())){ delta.addChangeFlags(ICDescriptionDelta.NAME); } - + ICSourceEntry newEntries[] = newCfg.getSourceEntries(); ICSourceEntry oldEntries[] = oldCfg.getSourceEntries(); - + if(newEntries.length > oldEntries.length){ delta.addChangeFlags(ICDescriptionDelta.SOURCE_ADDED); } else { @@ -2220,14 +1438,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + if(!found){ delta.addChangeFlags(ICDescriptionDelta.SOURCE_ADDED); break; } } } - + if(oldEntries.length > newEntries.length){ delta.addChangeFlags(ICDescriptionDelta.SOURCE_REMOVED); } else { @@ -2241,14 +1459,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + if(!found){ delta.addChangeFlags(ICDescriptionDelta.SOURCE_REMOVED); break; } } } - + try { CConfigurationSpecSettings newSettings = newInfo.getSpecSettings(); CConfigurationSpecSettings oldSettings = oldInfo.getSpecSettings(); @@ -2258,9 +1476,9 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { CCorePlugin.log(e); } - + calculateCfgExtSettingsDelta(delta); - + int drFlags = calculateDescriptorFlags(newCfg, oldCfg); if(drFlags != 0) delta.addChangeFlags(drFlags); @@ -2268,13 +1486,13 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return delta.isEmpty() ? null : delta; } - + private void calculateCfgExtSettingsDelta(CProjectDescriptionDelta delta){ ICConfigurationDescription newDes = (ICConfigurationDescription)delta.getNewSetting(); ICConfigurationDescription oldDes = (ICConfigurationDescription)delta.getOldSetting(); ExtSettingsDelta[] deltas = getSettingChange(newDes, oldDes); int flags = 0; - int addedRemoved = ICDescriptionDelta.EXTERNAL_SETTINGS_ADDED | ICDescriptionDelta.EXTERNAL_SETTINGS_REMOVED; + int addedRemoved = ICDescriptionDelta.EXTERNAL_SETTINGS_ADDED | ICDescriptionDelta.EXTERNAL_SETTINGS_REMOVED; if(deltas != null ){ for(int i = 0; i < deltas.length; i++){ ICSettingEntry[][] d = deltas[i].getEntriesDelta(); @@ -2282,7 +1500,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { flags |= ICDescriptionDelta.EXTERNAL_SETTINGS_ADDED; if(d[1] != null) flags |= ICDescriptionDelta.EXTERNAL_SETTINGS_REMOVED; - + if((flags & (addedRemoved)) == addedRemoved) break; } @@ -2290,16 +1508,16 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { if(flags != 0) delta.addChangeFlags(flags); } - + int cfgRefFlags = calcRefChangeFlags(newDes, oldDes); if(cfgRefFlags != 0) delta.addChangeFlags(cfgRefFlags); } - + private int calcRefChangeFlags(ICConfigurationDescription newDes, ICConfigurationDescription oldDes){ - Map newMap = newDes != null ? newDes.getReferenceInfo() : null; + Map newMap = newDes != null ? newDes.getReferenceInfo() : null; Map oldMap = oldDes != null ? oldDes.getReferenceInfo() : null; - + int flags = 0; if(newMap == null || newMap.size() == 0){ if(oldMap != null && oldMap.size() != 0){ @@ -2310,8 +1528,8 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { flags = ICDescriptionDelta.CFG_REF_ADDED; } else { boolean stop = false; - for(Iterator> iter = newMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry newEntry = iter.next(); + for(Iterator iter = newMap.entrySet().iterator(); iter.hasNext();){ + Map.Entry newEntry = (Map.Entry)iter.next(); Object newProj = newEntry.getKey(); Object newCfg = newEntry.getValue(); Object oldCfg = oldMap.remove(newProj); @@ -2325,32 +1543,32 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + if(!oldMap.isEmpty()) flags |= ICDescriptionDelta.CFG_REF_REMOVED; } } - + return flags; } - + private ExtSettingsDelta[] getSettingChange(ICConfigurationDescription newDes, ICConfigurationDescription oldDes){ CExternalSetting[] newSettings = newDes != null ? (CExternalSetting[])newDes.getExternalSettings() : null; CExternalSetting[] oldSettings = oldDes != null ? (CExternalSetting[])oldDes.getExternalSettings() : null; return CExternalSettinsDeltaCalculator.getInstance().getSettingChange(newSettings, oldSettings); } - + private CProjectDescriptionDelta createDelta(ICFolderDescription newFo, ICFolderDescription oldFo){ CProjectDescriptionDelta delta = new CProjectDescriptionDelta(newFo, oldFo); - + if(delta.getDeltaKind() == ICDescriptionDelta.CHANGED){ ICLanguageSetting newLss[] = newFo.getLanguageSettings(); ICLanguageSetting oldLss[] = oldFo.getLanguageSettings(); List newList = new ArrayList(Arrays.asList(newLss)); List oldList = new ArrayList(Arrays.asList(oldLss)); List matched = sortSettings(newList, oldList); - + for(Iterator iter = matched.iterator(); iter.hasNext();){ ICLanguageSetting[] match = iter.next(); CProjectDescriptionDelta lsDelta = createDelta(match[0], match[1]); @@ -2379,7 +1597,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // if(lsDelta != null) // delta.addChild(lsDelta); // } - + // if(!oldMap.isEmpty()){ // for(Iterator iter = oldMap.values().iterator(); iter.hasNext();){ // delta.addChild(createDelta(null, (ICLanguageSetting)iter.next())); @@ -2388,14 +1606,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // if(!newFo.getPath().equals(oldFo.getPath())) // delta.addChangeFlags(ICProjectDescriptionDelta.PATH); - + if(newFo.isExcluded() != oldFo.isExcluded()) delta.addChangeFlags(ICDescriptionDelta.EXCLUDE); } - + return delta.isEmpty() ? null : delta; } - + private List sortSettings(List settings1, List settings2){ ICLanguageSetting setting1; @@ -2405,7 +1623,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { setting1 = iter1.next(); for(Iterator iter2 = settings2.iterator(); iter2.hasNext();){ setting2 = iter2.next(); - + if(setting2.getId().equals(setting1.getId())){ iter1.remove(); iter2.remove(); @@ -2417,14 +1635,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } } - + for(Iterator iter1 = settings1.iterator(); iter1.hasNext();){ setting1 = iter1.next(); String lId = setting1.getLanguageId(); if(lId != null){ for(Iterator iter2 = settings2.iterator(); iter2.hasNext();){ setting2 = iter2.next(); - + if(lId.equals(setting2.getLanguageId())){ iter1.remove(); iter2.remove(); @@ -2481,28 +1699,28 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return result; } - + private CProjectDescriptionDelta createDelta(ICFileDescription newFi, ICFileDescription oldFi){ CProjectDescriptionDelta delta = new CProjectDescriptionDelta(newFi, oldFi); - + if(delta.getDeltaKind() == ICDescriptionDelta.CHANGED){ CProjectDescriptionDelta lsDelta = createDelta(newFi.getLanguageSetting(), oldFi.getLanguageSetting()); if(lsDelta != null) delta.addChild(lsDelta); - + // if(!newFi.getPath().equals(oldFi.getPath())) // delta.addChangeFlags(ICProjectDescriptionDelta.PATH); - + if(newFi.isExcluded() != oldFi.isExcluded()) delta.addChangeFlags(ICDescriptionDelta.EXCLUDE); - } + } return delta.isEmpty() ? null : delta; } - + private CProjectDescriptionDelta createDelta(ICLanguageSetting newLs, ICLanguageSetting oldLs){ CProjectDescriptionDelta delta = new CProjectDescriptionDelta(newLs, oldLs); - + if(delta.getDeltaKind() == ICDescriptionDelta.CHANGED){ int kinds[] = KindBasedStore.getLanguageEntryKinds(); int kind; @@ -2514,7 +1732,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { ICLanguageSettingEntry newEntries[] = newLs.getSettingEntries(kind); ICLanguageSettingEntry oldEntries[] = oldLs.getSettingEntries(kind); boolean[] change = calculateSettingsChanges(newEntries, oldEntries); - + if(change[0]) addedKinds |= kind; if(change[1]) @@ -2525,23 +1743,23 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { delta.setAddedLanguageEntriesKinds(addedKinds); delta.setRemovedLanguageEntriesKinds(removedKinds); delta.setReorderedLanguageEntriesKinds(reorderedKinds); - + String[] newCtIds = newLs.getSourceContentTypeIds(); String[] oldCtIds = oldLs.getSourceContentTypeIds(); - + if(!Arrays.equals(newCtIds, oldCtIds)) delta.addChangeFlags(ICDescriptionDelta.SOURCE_CONTENT_TYPE); - - + + String[] newExts = newLs.getSourceExtensions(); String[] oldExts = oldLs.getSourceExtensions(); if(!Arrays.equals(newExts, oldExts)) delta.addChangeFlags(ICDescriptionDelta.SOURCE_ENTENSIONS); - + // newCt = newLs.getHeaderContentType(); // oldCt = oldLs.getHeaderContentType(); - + // if(!compare(newCt, oldCt)) // delta.addChangeFlags(ICDescriptionDelta.HEADER_CONTENT_TYPE); @@ -2550,10 +1768,10 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // if(!Arrays.equals(newExts, oldExts)) // delta.addChangeFlags(ICDescriptionDelta.HEADER_ENTENSIONS); } - + return delta.isEmpty() ? null : delta; } - + private boolean[] calculateSettingsChanges(ICLanguageSettingEntry newEntries[], ICLanguageSettingEntry oldEntries[]) { boolean result[] = new boolean[3]; @@ -2616,20 +1834,20 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { /* public boolean entriesEqual(ICLanguageSettingEntry entries1[], ICLanguageSettingEntry entries2[]){ if(entries1.length != entries2.length) return false; - + for(int i = 0; i < entries1.length; i++){ if(!entries1[i].equals(entries2[i])) return false; } - + return true; } -*/ +*/ private CProjectDescriptionDelta createDelta(ICTargetPlatformSetting newTPS, ICTargetPlatformSetting oldTPS){ CProjectDescriptionDelta delta = new CProjectDescriptionDelta(newTPS, oldTPS); if(!Arrays.equals(newTPS.getBinaryParserIds(), oldTPS.getBinaryParserIds())) delta.addChangeFlags(ICDescriptionDelta.BINARY_PARSER_IDS); - + return delta.isEmpty() ? null : delta; } @@ -2660,7 +1878,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { indexDelta = createDelta(indexCfg, oldIndexCfg); } if(indexDelta != null){ - List list = new ArrayList(); + List list = new ArrayList(); generateCElementDeltasFromCfgDelta(cProject, indexDelta, list); return list.toArray(new ICElementDelta[list.size()]); } @@ -2682,7 +1900,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { celementFlags |= ICElementDelta.F_ADDED_PATHENTRY_SOURCE; if((descriptionFlags & ICDescriptionDelta.SOURCE_REMOVED) != 0) celementFlags |= ICElementDelta.F_REMOVED_PATHENTRY_SOURCE; - + if(celementFlags != 0){ CElementDelta cElDelta = new CElementDelta(cProject.getCModel()); cElDelta.changed(cProject, celementFlags); @@ -2699,26 +1917,25 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { generateCElementDeltasFromResourceDelta(cProject, child, list); } } - break; case ICDescriptionDelta.ADDED: case ICDescriptionDelta.REMOVED: break; } return list; } - + private List generateCElementDeltasFromResourceDelta(ICProject cProject, ICDescriptionDelta delta, List list){ int kind = delta.getDeltaKind(); ICDescriptionDelta parentDelta = delta.getParent(); ICElement el; // IProject project = cProject.getProject(); IResource rc = null; - + ICResourceDescription oldRcDes; ICResourceDescription newRcDes; IPath path; switch(kind){ - case ICDescriptionDelta.REMOVED: + case ICDescriptionDelta.REMOVED: oldRcDes = (ICResourceDescription)delta.getOldSetting(); path = oldRcDes.getPath(); newRcDes = ((ICConfigurationDescription)parentDelta.getNewSetting()).getResourceDescription(path, false); @@ -2775,12 +1992,12 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } else { //ERROR? } - + } } return list; } - + private ICLanguageSetting getLanguageSetting(ICResourceDescription rcDes, String fileName){ if(rcDes.getType() == ICSettingBase.SETTING_FILE){ return ((ICFileDescription)rcDes).getLanguageSetting(); @@ -2791,10 +2008,10 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { private List generateCElementDeltasFromLanguageDelta(ICElement el, ICDescriptionDelta delta, List list){ if(delta == null) return list; - + int flags = 0; - flags |= calculateEntriesFlags(delta.getAddedEntriesKinds(), true); - flags |= calculateEntriesFlags(delta.getRemovedEntriesKinds(), false); + flags |= calculateEntriesFlags(delta.getAddedEntriesKinds(), true); + flags |= calculateEntriesFlags(delta.getRemovedEntriesKinds(), false); flags |= calculateEntriesFlags(delta.getReorderedEntriesKinds(), true); if(flags != 0){ CElementDelta cElDelta = new CElementDelta(el.getCModel()); @@ -2803,30 +2020,30 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return list; } - + private int calculateEntriesFlags(int languageDeltaKinds, boolean added){ int flags = 0; int kindsArray[] = kindsToArray(languageDeltaKinds); - + for(int i = 0; i < kindsArray.length; i++){ switch(kindsArray[i]){ - case ICSettingEntry.INCLUDE_PATH: + case ICLanguageSettingEntry.INCLUDE_PATH: flags |= ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE; break; - case ICSettingEntry.INCLUDE_FILE: + case ICLanguageSettingEntry.INCLUDE_FILE: flags |= ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE; break; - case ICSettingEntry.MACRO: + case ICLanguageSettingEntry.MACRO: flags |= ICElementDelta.F_CHANGED_PATHENTRY_MACRO; break; - case ICSettingEntry.MACRO_FILE: + case ICLanguageSettingEntry.MACRO_FILE: flags |= ICElementDelta.F_CHANGED_PATHENTRY_MACRO; break; - case ICSettingEntry.LIBRARY_PATH: + case ICLanguageSettingEntry.LIBRARY_PATH: flags |= added ? ICElementDelta.F_ADDED_PATHENTRY_LIBRARY : ICElementDelta.F_REMOVED_PATHENTRY_LIBRARY; break; - case ICSettingEntry.LIBRARY_FILE: + case ICLanguageSettingEntry.LIBRARY_FILE: flags |= added ? ICElementDelta.F_ADDED_PATHENTRY_LIBRARY : ICElementDelta.F_REMOVED_PATHENTRY_LIBRARY; break; @@ -2834,7 +2051,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return flags; } - + int[] kindsToArray(int kinds){ int allKinds[] = KindBasedStore.getLanguageEntryKinds(); int kindsArray[] = new int[allKinds.length]; @@ -2844,7 +2061,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { kindsArray[num++] = allKinds[i]; } } - + if(num < allKinds.length){ int tmp[] = new int[num]; if(num > 0) @@ -2853,171 +2070,42 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return kindsArray; } - - public void addCProjectDescriptionListener(ICProjectDescriptionListener listener, int eventTypes){ - synchronized(fListeners){ - fListeners.add(new ListenerDescriptor(listener, eventTypes)); - } + + /* + * Methods for manipulating the set of project description listeners + */ + + public void addCProjectDescriptionListener(ICProjectDescriptionListener listener, int eventTypes) { + fListeners.add(new ListenerDescriptor(listener, eventTypes)); } - public void removeCProjectDescriptionListener(ICProjectDescriptionListener listener){ - synchronized(fListeners){ - int size = fListeners.size(); - ListenerDescriptor des; - for(int i = 0; i < size; i++){ - des = fListeners.get(i); - if(des.fListener == listener){ - fListeners.remove(des); - break; - } - } - } + public void removeCProjectDescriptionListener(ICProjectDescriptionListener listener) { + fListeners.remove(listener); } - - private ListenerDescriptor[] getListeners(){ - synchronized(fListeners){ - return fListeners.toArray(new ListenerDescriptor[fListeners.size()]); - } - } - - void notifyListeners(CProjectDescriptionEvent event){ - ListenerDescriptor[] listeners = getListeners(); + + public void notifyListeners(CProjectDescriptionEvent event){ int eventType = event.getEventType(); - for(int i = 0; i < listeners.length; i++){ - if(listeners[i].handlesEvent(eventType)){ - listeners[i].fListener.handleEvent(event); - } + for (ListenerDescriptor listener : fListeners) { + if (listener.handlesEvent(eventType)) + listener.fListener.handleEvent(event); } } - - public Element createXmlElementCopy(InternalXmlStorageElement el) throws CoreException{ - try { - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = builder.newDocument(); - Element newXmlEl = null; - if(el.fElement.getParentNode().getNodeType() == Node.DOCUMENT_NODE){ - Document baseDoc = el.fElement.getOwnerDocument(); - NodeList list = baseDoc.getChildNodes(); - for(int i = 0; i < list.getLength(); i++){ - Node node = list.item(i); - node = importAddNode(doc, node); - if(node.getNodeType() == Node.ELEMENT_NODE && newXmlEl == null){ - newXmlEl = (Element)node; - } - } - - } else { - newXmlEl = (Element)importAddNode(doc, el.fElement); - } -// Document baseDoc = el.fElement.getOwnerDocument(); -// Element baseEl = baseDoc.getDocumentElement(); -// Element newXmlEl = (Element)doc.importNode(baseEl, true); - -// doc.appendChild(newXmlEl); - return newXmlEl; - } catch (ParserConfigurationException e) { - throw ExceptionFactory.createCoreException(e); - } catch (FactoryConfigurationError e) { - throw ExceptionFactory.createCoreException(e); - } - - } - - InternalXmlStorageElement copyConfigurationElement(InternalXmlStorageElement el, String newId, boolean readOnly) throws CoreException { - el = copyElement(el, readOnly); - el.setAttribute(CConfigurationSpecSettings.ID, newId); - return el; - } - - InternalXmlStorageElement copyElement(InternalXmlStorageElement el, boolean readOnly) throws CoreException { -// try { -// DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); -// Document doc = builder.newDocument(); -// Element newXmlEl = null; -// if(el.fElement.getParentNode().getNodeType() == Node.DOCUMENT_NODE){ -// Document baseDoc = el.fElement.getOwnerDocument(); -// NodeList list = baseDoc.getChildNodes(); -// for(int i = 0; i < list.getLength(); i++){ -// Node node = list.item(i); -// node = importAddNode(doc, node); -// if(node.getNodeType() == Node.ELEMENT_NODE && newXmlEl == null){ -// newXmlEl = (Element)node; -// } -// } -// -// } -// -// -//// = (Element)doc.importNode(el.fElement, true); -// -//// Document baseDoc = el.fElement.getOwnerDocument(); -//// Element baseEl = baseDoc.getDocumentElement(); -//// Element newXmlEl = (Element)doc.importNode(baseEl, true); -// -// -//// doc.appendChild(newXmlEl); -// return new InternalXmlStorageElement(newXmlEl, el.getParent(), -// el.isParentRefAlowed(), el.getAttributeFilters(), -// el.getChildFilters(), readOnly); -// } catch (ParserConfigurationException e) { -// throw ExceptionFactory.createCoreException(e); -// } catch (FactoryConfigurationError e) { -// throw ExceptionFactory.createCoreException(e); -// } - Element newXmlEl = createXmlElementCopy(el); - return new InternalXmlStorageElement(newXmlEl, el.getParent(), - el.isParentRefAlowed(), el.getAttributeFilters(), - el.getChildFilters(), readOnly); - } - - private Node importAddNode(Document doc, Node node){ - if(node.getOwnerDocument().equals(doc)){ - node = node.cloneNode(true); - } else { - node = doc.importNode(node, true); - } - - return doc.appendChild(node); - } - - CStorage copyStorage(CStorage el, boolean readOnly) throws CoreException { - try { - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = builder.newDocument(); - Element newXmlEl = (Element)doc.importNode(el.fElement, true); - -// Document baseDoc = el.fElement.getOwnerDocument(); -// Element baseEl = baseDoc.getDocumentElement(); -// Element newXmlEl = (Element)doc.importNode(baseEl, true); - - - doc.appendChild(newXmlEl); - return new CStorage(newXmlEl, readOnly); - } catch (ParserConfigurationException e) { - throw ExceptionFactory.createCoreException(e); - } catch (FactoryConfigurationError e) { - throw ExceptionFactory.createCoreException(e); - } - - } - void checkRemovedConfigurations(ICDescriptionDelta delta){ if(delta == null) return; - + ICDescriptionDelta cfgDeltas[] = delta.getChildren(); for(int i = 0; i < cfgDeltas.length; i++){ if(cfgDeltas[i].getDeltaKind() == ICDescriptionDelta.REMOVED){ CConfigurationDescriptionCache des = (CConfigurationDescriptionCache)cfgDeltas[i].getOldSetting(); - CConfigurationData data = des.getConfigurationData(); + CConfigurationData data = des.getConfigurationData(); try { removeData(des, data, null); } catch (CoreException e) { } } } - } public ICConfigurationDescription getPreferenceConfiguration(String buildSystemId) throws CoreException { @@ -3032,7 +2120,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { monitor.done(); } } - + public ICConfigurationDescription getPreferenceConfiguration(String buildSystemId, boolean write) throws CoreException { ICConfigurationDescription des = getLoaddedPreference(buildSystemId); if(des == null){ @@ -3041,7 +2129,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } catch (CoreException e) { // CCorePlugin.log(e); } - + if(des == null){ try { des = createNewPreference(buildSystemId); @@ -3049,7 +2137,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { CCorePlugin.log(e); } } - + setLoaddedPreference(buildSystemId, (CConfigurationDescriptionCache)des); } if(des != null && write){ @@ -3061,23 +2149,23 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } return des; } - + public void setPreferenceConfiguration(String buildSystemId, ICConfigurationDescription des) throws CoreException{ if(!needSavePreference(buildSystemId, des)) return; - + CConfigurationDescriptionCache cache = createPreferenceCache(des); - + savePreferenceConfiguration(buildSystemId, cache); - + setLoaddedPreference(buildSystemId, cache); } - + private void savePreferenceConfiguration(String buildStystemId, CConfigurationDescriptionCache cache) throws CoreException{ ICStorageElement el = cache.getSpecSettings().getRootStorageElement(); saveBuildSystemConfigPreferenceStorage(buildStystemId, el); } - + private void saveBuildSystemConfigPreferenceStorage(String buildSystemId, ICStorageElement el) throws CoreException{ ICStorageElement cur = getBuildSystemConfigPreferenceStorage(buildSystemId); ICStorageElement parent = cur.getParent(); @@ -3085,20 +2173,20 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { parent.importChild(el); savePreferenceStorage(PREFERENCES_STORAGE, MODULE_ID, parent); } - + private boolean needSavePreference(String buildSystemId, ICConfigurationDescription des){ if(des.isModified() || !des.isPreferenceConfiguration() || !des.getBuildSystemId().equals(buildSystemId)) return true; - + return false; } - + private ICConfigurationDescription createWritablePreference(CConfigurationDescriptionCache cache) throws CoreException{ return new CConfigurationDescription(cache, fPrefUpdater); } - + private CConfigurationDescriptionCache createPreferenceCache(ICConfigurationDescription des) throws CoreException{ IInternalCCfgInfo cfgDes = (IInternalCCfgInfo)des; CConfigurationData baseData = cfgDes.getConfigurationData(false); @@ -3122,29 +2210,29 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { runContextOperations(context, null); return cache; } - + private ICConfigurationDescription createNewPreference(String buildSystemId) throws CoreException { ICStorageElement cfgEl = getBuildSystemConfigPreferenceStorage(buildSystemId, true, false); - + String id = PREFERENCE_CFG_ID_PREFIX + buildSystemId; CConfigurationDescription des = new CConfigurationDescription(id, PREFERENCE_CFG_NAME, buildSystemId, cfgEl, fPrefUpdater); - + return createPreferenceCache(des); } - -// private CStorage createBuildSystemCfgPrefStore() throws CoreException{ + +// private XmlStorage createBuildSystemCfgPrefStore() throws CoreException{ // ICStorageElement el = getPreferenceStorage(PREFERENCES_STORAGE, MODULE_ID, true, false); -// -// CStorage store = new CStorage((InternalXmlStorageElement)el); -// +// +// XmlStorage store = new XmlStorage((InternalXmlStorageElement)el); +// // return store; // } -// +// // ICSettingsStorage getBuildSystemCfgPrefStore() throws CoreException{ // if(fPrefCfgStorage == null){ // fPrefCfgStorage = createBuildSystemCfgPrefStore(); // } -// +// // return copyStorage(fPrefCfgStorage, false); // } @@ -3155,7 +2243,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { private ICStorageElement getBuildSystemConfigPreferenceStorage(String buildSystemId, boolean createIfNotDound, boolean readOnly) throws CoreException{ ICStorageElement el = getPreferenceStorage(PREFERENCES_STORAGE, MODULE_ID, createIfNotDound, readOnly); ICStorageElement cfgEl = null; - + if(el != null){ ICStorageElement children[] = el.getChildren(); for(int i = 0; i < children.length; i++){ @@ -3166,22 +2254,22 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + } - + if(cfgEl == null){ cfgEl = el.createChild(PREFERENCE_BUILD_SYSTEM_ELEMENT); cfgEl.setAttribute(ID, buildSystemId); } - + } - + return cfgEl; } - + private ICConfigurationDescription loadPreference(String buildSystemId) throws CoreException{ ICStorageElement el = getPreferenceStorage(PREFERENCES_STORAGE, MODULE_ID, false, false); - + ICStorageElement children[] = el.getChildren(); ICStorageElement cfgEl = null; for(int i = 0; i < children.length; i++){ @@ -3192,7 +2280,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { break; } } - + } CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache(cfgEl, null); CSettingEntryFactory factory = new CSettingEntryFactory(); @@ -3201,29 +2289,29 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { factory.clear(); return cache; } - + public ICStorageElement getPreferenceStorage(String prefKey, String storageId, boolean createIfNotDound, boolean readOnly) throws CoreException{ - CStorage store = getPreferenceStore(prefKey, createIfNotDound, readOnly); - + XmlStorage store = getPreferenceStore(prefKey, createIfNotDound, readOnly); + return store.getStorage(storageId, createIfNotDound); } - - private CStorage getPreferenceStore(String prefKey, boolean createIfNotDound, boolean readOnly) throws CoreException{ + + private XmlStorage getPreferenceStore(String prefKey, boolean createIfNotDound, boolean readOnly) throws CoreException{ ICStorageElement el = createPreferenceStorage(prefKey, createIfNotDound, readOnly); - - CStorage store = new CStorage((InternalXmlStorageElement)el); - + + XmlStorage store = new XmlStorage((InternalXmlStorageElement)el); + return store; } - + public void savePreferenceStorage(String prefKey, String storageId, ICStorageElement el) throws CoreException{ - CStorage store = getPreferenceStore(prefKey, true, false); + XmlStorage store = getPreferenceStore(prefKey, true, false); store.importStorage(storageId, el); - - ICStorageElement rootEl = new InternalXmlStorageElement(store.fElement, store.isReadOnly()); + + InternalXmlStorageElement rootEl = new InternalXmlStorageElement(store.fElement, store.isReadOnly()); serializePreference(prefKey, rootEl); } - + private CConfigurationDescriptionCache getLoaddedPreference(String buildSystemId){ return fPreferenceMap.get(buildSystemId); } @@ -3243,17 +2331,17 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { public CConfigurationData createDefaultConfigData(IProject project, String id, String name, CDataFactory factory) throws CoreException{ if(factory == null) factory = new CDataFactory(); - + CConfigurationData data = CDataUtil.createEmptyData(id, name, factory, true); // CDataUtil. //// data.initEmptyData(); -// +// // CDataUtil.adjustConfig(data, factory); factory.setModified(data, false); return data; } - + public boolean isNewStyleIndexCfg(IProject project){ ICProjectDescription des = getProjectDescription(project, false); if(des != null) @@ -3267,7 +2355,7 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return isNewStyleCfg(cfgDes); return false; } - + public boolean isNewStyleProject(IProject project){ return isNewStyleProject(getProjectDescription(project, false)); } @@ -3275,24 +2363,24 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { public boolean isNewStyleProject(ICProjectDescription des){ if(des == null) return false; - + return isNewStyleIndexCfg(des); } public boolean isNewStyleCfg(ICConfigurationDescription cfgDes){ if(cfgDes == null) return false; - + CConfigurationData data = ((IInternalCCfgInfo)cfgDes).getConfigurationData(false); if(data instanceof CConfigurationDescriptionCache){ data = ((CConfigurationDescriptionCache)data).getConfigurationData(); } - + return data != null && !PathEntryConfigurationDataProvider.isPathEntryData(data); } - + // public String[] getContentTypeFileSpecs (IProject project, IContentType type) { -// String[] globalSpecs = type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC); +// String[] globalSpecs = type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC); // IContentTypeSettings settings = null; // if (project != null) { // IScopeContext projectScope = new ProjectScope(project); @@ -3308,53 +2396,31 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { // for (int j=0; j map = getDescriptionApplyingMap(false); - if(map != null) - return map.get(project); - return null; - } - - void setDescriptionApplying(IProject project, ICProjectDescription des){ - if(des == null){ - clearDescriptionApplying(project); - } else { - Map map = getDescriptionApplyingMap(true); - map.put(project, des); - } - } - - void clearDescriptionApplying(IProject project){ - Map map = getDescriptionApplyingMap(false); - if(map != null) - map.remove(project); - } - + static ICLanguageSetting getLanguageSettingForFile(ICConfigurationDescription cfgDes, IPath path, boolean ignoreExcludeStatus){ - int segCount = path.segmentCount(); + int segCount = path.segmentCount(); if(segCount == 0) return null; - + ICResourceDescription rcDes = cfgDes.getResourceDescription(path, false); if(rcDes == null || (!ignoreExcludeStatus && rcDes.isExcluded())) return null; - + if(rcDes.getType() == ICSettingBase.SETTING_FOLDER){ return ((ICFolderDescription)rcDes).getLanguageSettingForFile(path.lastSegment()); } @@ -3363,17 +2429,17 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { static private HashMap, CLanguageData> createExtSetToLDataMap(IProject project, CLanguageData[] lDatas){ HashMap, CLanguageData> map = new HashMap, CLanguageData>(); - + for(int i = 0; i < lDatas.length; i++){ CLanguageData lData = lDatas[i]; String[] exts = CDataUtil.getSourceExtensions(project, lData); HashSet set = new HashSet(Arrays.asList(exts)); map.put(set, lData); } - + return map; } - + static boolean removeNonCustomSettings(IProject project, CConfigurationData data){ PathSettingsContainer cr = CDataUtil.createRcDataHolder(data); PathSettingsContainer[] crs = cr.getChildren(false); @@ -3385,17 +2451,16 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { childRcData = (CResourceData)child.getValue(); if(childRcData.getType() == ICSettingBase.SETTING_FOLDER){ CResourceData parentRcData = null; - for(parent = child.getParentContainer(); + for(parent = child.getParentContainer(); (parentRcData = (CResourceData)parent.getValue()).getType() != ICSettingBase.SETTING_FOLDER; - parent = parent.getParentContainer()) { - if(!settingsCustomized(project, (CFolderData)parentRcData, (CFolderData)childRcData)){ - try { - data.removeResourceData(childRcData); - child.remove(); - modified = true; - } catch (CoreException e) { - CCorePlugin.log(e); - } + parent = parent.getParentContainer()); + if(!settingsCustomized(project, (CFolderData)parentRcData, (CFolderData)childRcData)){ + try { + data.removeResourceData(childRcData); + child.remove(); + modified = true; + } catch (CoreException e) { + CCorePlugin.log(e); } } } else { @@ -3410,32 +2475,32 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } } - + } return modified; } - + static boolean settingsCustomized(IProject project, CFolderData parent, CFolderData child){ if(baseSettingsCustomized(parent, child)) return true; CLanguageData[] childLDatas = child.getLanguageDatas(); CLanguageData[] parentLDatas = parent.getLanguageDatas(); - + if(childLDatas.length != parentLDatas.length) return true; - + if(childLDatas.length != 0){ HashMap, CLanguageData> parentMap = createExtSetToLDataMap(project, parentLDatas); HashMap, CLanguageData> childMap = createExtSetToLDataMap(project, childLDatas); CLanguageData parentLData, childLData; - for(Iterator, CLanguageData>> iter = parentMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry, CLanguageData> entry = iter.next(); + for(Iterator iter = parentMap.entrySet().iterator(); iter.hasNext();){ + Map.Entry entry = (Map.Entry)iter.next(); childLData = childMap.get(entry.getKey()); if(childLData == null) return true; - - parentLData = entry.getValue(); + + parentLData = (CLanguageData)entry.getValue(); if(!langDatasEqual(parentLData, childLData)) return true; } @@ -3457,21 +2522,21 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { String fileName = childPath.lastSegment(); if(PatternNameMap.isPatternName(fileName)) return true; - + CLanguageData parentLangData = CDataUtil.findLanguagDataForFile(fileName, project, foParent); - + return !langDatasEqual(lData, parentLangData); - } - + } + CFileData fiParent = (CFileData)parent; CLanguageData parentLangData = fiParent.getLanguageData(); return !langDatasEqual(lData, parentLangData); } - + static boolean langDatasEqual(CLanguageData lData1, CLanguageData lData2){ if(lData1 == null) return lData2 == null; - + if(lData2 == null) return false; @@ -3484,21 +2549,21 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { if(!Arrays.equals(entries1, entries2)) return false; } - + return true; } - + private static boolean baseSettingsCustomized(CResourceData parent, CResourceData child){ // if(parent.isExcluded() != child.isExcluded()) // return true; - + if(child.hasCustomSettings()) return true; - + return false; } - + public ICProjectDescriptionWorkspacePreferences getProjectDescriptionWorkspacePreferences( boolean write) { if(fPreferences == null){ @@ -3509,12 +2574,12 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { if(fPreferences == null) fPreferences = new CProjectDescriptionWorkspacePreferences((ICStorageElement)null, null, true); } - + CProjectDescriptionWorkspacePreferences prefs = fPreferences; - + if(write) prefs = new CProjectDescriptionWorkspacePreferences(prefs, false); - + return prefs; } @@ -3534,14 +2599,14 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } } } while(false); - + if(changed){ CProjectDescriptionWorkspacePreferences basePrefs; if(prefs instanceof CProjectDescriptionWorkspacePreferences) basePrefs = (CProjectDescriptionWorkspacePreferences)prefs; else throw new IllegalArgumentException(); - + fPreferences = new CProjectDescriptionWorkspacePreferences(basePrefs, null, true); storePreferences(fPreferences); @@ -3554,16 +2619,16 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { } finally { monitor.done(); } - + return changed; } - + private void storePreferences(CProjectDescriptionWorkspacePreferences prefs) throws CoreException { ICStorageElement el = getCProjectDescriptionPreferencesElement(true, false); prefs.serialize(el); saveCProjectDescriptionPreferencesElement(el); } - + private void saveCProjectDescriptionPreferencesElement(ICStorageElement el) throws CoreException{ ICStorageElement cur = getCProjectDescriptionPreferencesElement(true, false); ICStorageElement parent = cur.getParent(); @@ -3574,9 +2639,9 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { private CProjectDescriptionWorkspacePreferences loadPreferences() throws CoreException{ ICStorageElement el = getCProjectDescriptionPreferencesElement(false, true); - return new CProjectDescriptionWorkspacePreferences(el, null, true); + return new CProjectDescriptionWorkspacePreferences(el, null, true); } - + private ICStorageElement getCProjectDescriptionPreferencesElement(boolean createIfNotFound, boolean readOnly) throws CoreException{ ICStorageElement el = getPreferenceStorage(PREFERENCES_STORAGE, MODULE_ID, createIfNotFound, readOnly); ICStorageElement[] children = el.getChildren(); @@ -3588,15 +2653,15 @@ public class CProjectDescriptionManager implements ICProjectDescriptionManager { return el.createChild(PREFERENCES_ELEMENT); throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.14")); //$NON-NLS-1$ } - + public void updateExternalSettingsProviders(String[] ids, IProgressMonitor monitor){ ExtensionContainerFactory.updateReferencedProviderIds(ids, monitor); } - + boolean isEmptyCreatingDescriptionAllowed(){ return fAllowEmptyCreatingDescription; } - + void setEmptyCreatingDescriptionAllowed(boolean allow){ fAllowEmptyCreatingDescription = allow; } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionStorageManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionStorageManager.java new file mode 100644 index 00000000000..bd7ea1bce96 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CProjectDescriptionStorageManager.java @@ -0,0 +1,402 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.settings.model; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.internal.core.CConfigBasedDescriptorManager; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType.CProjectDescriptionStorageTypeProxy; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage; +import org.eclipse.cdt.internal.core.settings.model.xml2.XmlProjectDescriptionStorage2; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.resources.ResourceAttributes; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.osgi.framework.Version; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; + +/** + * Class that marshals creation of AbstractCProjectDescriptionStorages + * for a given project. + * + * Persist Storage type ID in the .cproject file, and provides backwards compatibility + * for existing project descriptions which don't encode the storage type in the project + * description. + */ +public class CProjectDescriptionStorageManager { + + /* Extension point data */ + /** CProjectDescriptionStorage extension point ID */ + private static final String CPROJ_DESC_STORAGE_EXT_ID = "CProjectDescriptionStorage"; //$NON-NLS-1$ + /** storage type element ID */ + private static final String CPROJ_STORAGE_TYPE = "CProjectStorageType"; //$NON-NLS-1$ + + // TODO provide some UI to select this + /** Default project description Storage type */ + private static final String DEFAULT_STORAGE_TYPE = XmlProjectDescriptionStorage.STORAGE_TYPE_ID; // XmlProjectDescriptionStorage2.STORAGE_TYPE_ID; + /** Default project description Storage version */ + private static final Version DEFAULT_STORAGE_VERSION = XmlProjectDescriptionStorage.STORAGE_DESCRIPTION_VERSION; // XmlProjectDescriptionStorage2.STORAGE_DESCRIPTION_VERSION; + + /** Map of StorageType ID -> List of StorageTypes */ + private volatile Map> storageTypeMap; + /** Map from IProject -> AbstractCProjectDescriptionStorage which is responsible for (de)serializing the project */ + private Map fDescriptionStorageMap = Collections.synchronizedMap(new HashMap()); + + + private volatile static CProjectDescriptionStorageManager instance; + + private CProjectDescriptionStorageManager() {} + + public static CProjectDescriptionStorageManager getInstance() { + if (instance == null) { + synchronized (CProjectDescriptionStorageManager.class) { + if (instance == null) + instance = new CProjectDescriptionStorageManager(); + } + } + return instance; + } + + + /** + * Return a AbstractCProjectDescriptionStorage for a particular project or + * null if none were found and the default storage type wasn't found + * @param project + * @return project description storage or null + */ + public AbstractCProjectDescriptionStorage getProjectDescriptionStorage(IProject project) { + AbstractCProjectDescriptionStorage projStorage = fDescriptionStorageMap.get(project); + if (projStorage == null) { + projStorage = loadProjectStorage(project); + fDescriptionStorageMap.put(project, projStorage); + } + return projStorage; + } + + /** + * Sets the Project description by delegating to the appropriate project storage type. + * + * If the storage type returns false on {@link ICProjectDescriptionStorageType#createsCProjectXMLFile()} then + * we create a .cproject file with type id and version. + * + * If no existing project storage is found then we throw a core exception (users should have called + * #getProjectDescriptionStorage(...) before calling this. + * + * @param project + * @param description + * @throws CoreException on failure + */ + public void setProjectDescription(IProject project, ICProjectDescription description, int flags, IProgressMonitor monitor) throws CoreException { + AbstractCProjectDescriptionStorage storage = fDescriptionStorageMap.get(project); + if (storage == null) + throw ExceptionFactory.createCoreException("Can't set ProjectDescription before getProjectDescriptionStorage!"); + if (!storage.type.createsCProjectXMLFile()) + writeProjectStorageType(project, storage.type); + storage.setProjectDescription(description, flags, monitor); + } + + + /** + * Persist the type and version of this particular project description storage type + * (for description storages that don't perform this job themselves). + * @param project + * @param type + */ + private void writeProjectStorageType(IProject project, CProjectDescriptionStorageTypeProxy type) throws CoreException{ + Document doc; + try { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + // Set the version + ProcessingInstruction instruction = doc.createProcessingInstruction(ICProjectDescriptionStorageType.STORAGE_VERSION_NAME, type.version.toString()); + doc.appendChild(instruction); + // Set the type id + Element el = doc.createElement(ICProjectDescriptionStorageType.STORAGE_ROOT_ELEMENT_NAME); + el.setAttribute(ICProjectDescriptionStorageType.STORAGE_TYPE_ATTRIBUTE, type.id); + doc.appendChild(el); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + DOMSource source = new DOMSource(doc); + StreamResult result = new StreamResult(stream); + transformer.transform(source, result); + + InputStream input = new ByteArrayInputStream(stream.toByteArray()); + + // Set the project description storage type + IFile f = project.getFile(ICProjectDescriptionStorageType.STORAGE_FILE_NAME); + if (!f.exists()) + f.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); + ensureWritable(f); + if (!f.exists()) + f.create(input, true, new NullProgressMonitor()); + else + f.setContents(input, IResource.FORCE, new NullProgressMonitor()); + } catch (ParserConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (TransformerConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (TransformerFactoryConfigurationError e) { + throw ExceptionFactory.createCoreException(e); + } catch (TransformerException e) { + throw ExceptionFactory.createCoreException(e); + } + } + + + /** + * Given a project, this method attempts to discover the type of the storage + * and return the AbstractCProjectDescriptionStorage responsible for loading it. + * + * @return AbstractCProjectDescription or null if not found + */ + private AbstractCProjectDescriptionStorage loadProjectStorage(IProject project) { + if (storageTypeMap == null) + initExtensionPoints(); + + // If no project description found, then use the default + Version version = DEFAULT_STORAGE_VERSION; + String storageTypeID = DEFAULT_STORAGE_TYPE; + + InputStream stream = null; + try{ + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + stream = getInputStreamForIFile(project, ICProjectDescriptionStorageType.STORAGE_FILE_NAME); + if(stream != null){ + Document doc = builder.parse(stream); + // Get the first element in the project file + Node rootElement = doc.getFirstChild(); + if (rootElement.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.7")); //$NON-NLS-1$ + else + version = new Version(rootElement.getNodeValue()); + + // Now get the project root element (there should be only one) + NodeList nodes = doc.getElementsByTagName(ICProjectDescriptionStorageType.STORAGE_ROOT_ELEMENT_NAME); + if (nodes.getLength() == 0) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.9")); //$NON-NLS-1$ + Node node = nodes.item(0); + if(node.getNodeType() != Node.ELEMENT_NODE) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.10")); //$NON-NLS-1$ + // If we've got this far, then we're at least dealing with an old style project: + // as this didn't use to provide a type, specify one explicitly + // Choose new style -- separated out storage modules by default as this is backwards compatible... + storageTypeID = XmlProjectDescriptionStorage2.STORAGE_TYPE_ID; + if (((Element)node).hasAttribute(ICProjectDescriptionStorageType.STORAGE_TYPE_ATTRIBUTE)) + storageTypeID = ((Element)node).getAttribute(ICProjectDescriptionStorageType.STORAGE_TYPE_ATTRIBUTE); + } + } catch (Exception e) { + // Catch all, if not found, we use the old-style defaults... + } finally { + if(stream != null){ + try { + stream.close(); + } catch (IOException e) {} + } + } + + List types = storageTypeMap.get(storageTypeID); + if (types != null) { + for (CProjectDescriptionStorageTypeProxy type : types) { + if (type.isCompatible(version)) { + return type.getProjectDescriptionStorage(type, project, version); + } + } + } + + // No type found! + CCorePlugin.log("CProjectDescriptionStorageType: " + storageTypeID + " for version: " + version + " not found!"); + return null; + } + + + private InputStream getInputStreamForIFile(IProject project, String name) throws CoreException { + IFile f = project.getFile(name); + if (f.exists()) + return f.getContents(true); + else { + URI location = f.getLocationURI(); + if (location != null) { + IFileStore file = EFS.getStore(location); + IFileInfo info = null; + + if (file != null) { + info = file.fetchInfo(); + if (info != null && info.exists()) + return file.openInputStream(EFS.NONE, null); + } + } + } + throw ExceptionFactory.createCoreException("No project des file found..."); + } + + + /* + * Resource Change Callbacks + */ + + /** + * Callback indicating that a project has moved + * @param fromProject + * @param toProject + */ + void projectMove(IProject fromProject, IProject toProject) { + AbstractCProjectDescriptionStorage projStorage = fDescriptionStorageMap.get(fromProject); + if (projStorage != null) { + fDescriptionStorageMap.put(toProject, projStorage); + projStorage.projectMove(toProject); + fDescriptionStorageMap.remove(fromProject); + } + // Notify the CConfigBasedDescriptorManager as well + CConfigBasedDescriptorManager.getInstance().projectMove(fromProject, toProject); + } + + /** + * Callback indicating project has been closed or deleted + * @param project + */ + void projectClosedRemove(IProject project) { + AbstractCProjectDescriptionStorage projStorage = fDescriptionStorageMap.get(project); + if (projStorage != null) + projStorage.projectCloseRemove(); + fDescriptionStorageMap.remove(project); + // Remove from ICDescriptorManager as well + CConfigBasedDescriptorManager.getInstance().projectClosedRemove(project); + } + + + + /** + * Cleanup state + */ + public void shutdown() { + instance = null; + } + + + /** + * Initialize the project description storage types + */ + private synchronized void initExtensionPoints() { + if (storageTypeMap != null) + return; + Map> m = new HashMap>(); + IExtensionPoint extpoint = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID, CPROJ_DESC_STORAGE_EXT_ID); + for (IExtension extension : extpoint.getExtensions()) { + for (IConfigurationElement configEl : extension.getConfigurationElements()) { + if (configEl.getName().equalsIgnoreCase(CPROJ_STORAGE_TYPE)) { + CProjectDescriptionStorageTypeProxy type = initStorageType(configEl); + if (type != null) { + if (!m.containsKey(type.id)) + m.put(type.id, new LinkedList()); + m.get(type.id).add(type); + } + } + } + } + storageTypeMap = m; + } + + /** + * Initialize a storage type from a configuration element + * @param el + * @return + */ + private static CProjectDescriptionStorageTypeProxy initStorageType(IConfigurationElement el) { + CProjectDescriptionStorageTypeProxy type = null; + try { + type = new CProjectDescriptionStorageTypeProxy(el); + } catch (CoreException e) { + CCorePlugin.log("Couldn't instantiate CProjectDescriptionStorageType " + + el.getDeclaringExtension().getNamespaceIdentifier() + " " + e.getMessage()); + } catch (IllegalArgumentException e) { + CCorePlugin.log("Failed to load CProjectDescriptionStorageType " + + el.getDeclaringExtension().getNamespaceIdentifier() + " " + e.getMessage()); + } + return type; + } + + /** + * Helper method to ensure that a resource is writable. This means:
+ * - If the resource doesn't exist, it can be created (its parent is made writable)
+ * - If the resource exists and its a file, it's made writable
+ * - If the resource exists and its a directory, it and its children + * are made writable + * @param resource + * @throws CoreException on failure + */ + public static void ensureWritable(IResource resource) throws CoreException { + if (!resource.exists()) + resource.refreshLocal(IResource.DEPTH_INFINITE, null); + if (!resource.exists()) { + // If resource doesn't exist, ensure it can be created. + ResourceAttributes parentAttr = resource.getParent().getResourceAttributes(); + if (parentAttr.isReadOnly()) { + parentAttr.setReadOnly(false); + resource.getParent().setResourceAttributes(parentAttr); + } + } else { + // If resource exists, ensure it and children are writable + resource.accept(new IResourceVisitor() { + public boolean visit(IResource resource) throws CoreException { + ResourceAttributes resAttr = resource.getResourceAttributes(); + if (resAttr.isReadOnly()) { + resAttr.setReadOnly(false); + resource.setResourceAttributes(resAttr); + } + return true; + } + }); + } + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CStorage.java deleted file mode 100644 index acd862b0c6f..00000000000 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CStorage.java +++ /dev/null @@ -1,192 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 Intel 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: - * Intel Corporation - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.internal.core.settings.model; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.eclipse.cdt.core.settings.model.ICSettingsStorage; -import org.eclipse.cdt.core.settings.model.ICStorageElement; -import org.eclipse.core.runtime.CoreException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class CStorage implements ICSettingsStorage{ - private static final String MODULE_ELEMENT_NAME = "storageModule"; //$NON-NLS-1$ - private static final String MODULE_ID_ATTRIBUTE = "moduleId"; //$NON-NLS-1$ - Element fElement; - private Map fStorageElementMap = new HashMap(); - private boolean fChildrenInited; - private boolean fIsReadOnly; - private boolean fIsDirty; - - public CStorage(Element element, boolean isReadOnly){ - fElement = element; - fIsReadOnly = isReadOnly; - } - - public CStorage(InternalXmlStorageElement element){ - fElement = element.fElement; - fIsReadOnly = element.isReadOnly(); - element.storageCreated(this); - } - - public boolean isReadOnly(){ - return fIsReadOnly; - } - - private void initChildren(){ - if(fChildrenInited) - return; - fChildrenInited = true; - - NodeList children = fElement.getChildNodes(); - int size = children.getLength(); - for(int i = 0; i < size; i++){ - Node node = children.item(i); - if(node.getNodeType() != Node.ELEMENT_NODE) - continue; - if(!MODULE_ELEMENT_NAME.equals(node.getNodeName())) - continue; - - Element element = (Element)node; - String moduleId = element.getAttribute(MODULE_ID_ATTRIBUTE).trim(); - if(moduleId.length() == 0) - continue; - - createAddStorageElement(moduleId, element); - } - } - - private InternalXmlStorageElement createAddStorageElement(String id, Element element){ - InternalXmlStorageElement se = createStorageElement(element, fIsReadOnly); - fStorageElementMap.put(id, se); - return se; - } - - public static InternalXmlStorageElement createStorageElement(Element el, boolean isReadOnly){ - return new InternalXmlStorageElement(el, null, false, new String[]{MODULE_ID_ATTRIBUTE}, null, isReadOnly); - } - -// public ICStorageElement getStorage(String id){ -// return getStorage(id, true); -// } - - - public boolean containsStorage(String id) throws CoreException { - return getStorage(id, false) != null; - } - - public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException { - if(fIsReadOnly) - throw ExceptionFactory.createIsReadOnlyException(); - - removeStorage(id); - - InternalXmlStorageElement xmlStEl = (InternalXmlStorageElement)el; - Element xmlEl = xmlStEl.fElement; - Document thisDoc = fElement.getOwnerDocument(); - Document otherDoc = xmlEl.getOwnerDocument(); - if(!thisDoc.equals(otherDoc)){ - xmlEl = (Element)thisDoc.importNode(xmlEl, true); - } - - Element newEl = thisDoc.createElement(MODULE_ELEMENT_NAME); - NodeList nl = xmlEl.getChildNodes(); - for(int i = 0; i < nl.getLength(); i++){ - Node child = nl.item(i).cloneNode(true); - newEl.appendChild(child); - } - - xmlEl = newEl; - - xmlEl = (Element)fElement.appendChild(xmlEl); - xmlEl.setAttribute(MODULE_ID_ATTRIBUTE, id); - - fIsDirty = true; - - return createAddStorageElement(id, xmlEl); - } - - public ICStorageElement getStorage(String id, boolean create){ - initChildren(); - - InternalXmlStorageElement se = (InternalXmlStorageElement)fStorageElementMap.get(id); - if(se == null && create){ -// if(fIsReadOnly) -// throw ExceptionFactory.createIsReadOnlyException(); - - fIsDirty = true; - Document doc = fElement.getOwnerDocument(); - Element child = createStorageXmlElement(doc, id); - fElement.appendChild(child); - se = createAddStorageElement(id, child); - } - return se; - } - - public static Element createStorageXmlElement(Document doc, String storageId){ - Element child = doc.createElement(MODULE_ELEMENT_NAME); - child.setAttribute(MODULE_ID_ATTRIBUTE, storageId); - - return child; - } - - public void removeStorage(String id){ - initChildren(); - InternalXmlStorageElement se = (InternalXmlStorageElement)fStorageElementMap.remove(id); - - if(se != null){ - if(fIsReadOnly) - throw ExceptionFactory.createIsReadOnlyException(); - - fIsDirty = true; - fElement.removeChild(se.fElement); - se.removed(); - } - } - - public boolean isDirty(){ - if(fIsDirty) - return true; - - for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ - InternalXmlStorageElement el = (InternalXmlStorageElement)iter.next(); - if(el.isDirty()) - return true; - } - - return false; - } - - void setReadOnly(boolean readOnly, boolean keepModify){ - fIsReadOnly = readOnly; - fIsDirty &= keepModify; - for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ - InternalXmlStorageElement el = (InternalXmlStorageElement)iter.next(); - el.setReadOnly(readOnly, keepModify); - } - } - - public void setDirty(boolean isDirty){ - fIsDirty = isDirty; - - if(!fIsDirty){ - for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ - InternalXmlStorageElement el = (InternalXmlStorageElement)iter.next(); - el.setDirty(false); - } - } - } -} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgProxyCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgProxyCache.java index e2ae6be757d..aa6272a0b93 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgProxyCache.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgProxyCache.java @@ -20,7 +20,7 @@ import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; import org.eclipse.core.runtime.IPath; public class CfgProxyCache implements IProxyCache { - private HashMap fProxyMap = new HashMap(); + private HashMap fProxyMap = new HashMap(); private PathSettingsContainer fPathContainer; CfgProxyCache(PathSettingsContainer pathDesContainer){ @@ -69,21 +69,21 @@ public class CfgProxyCache implements IProxyCache { } public CDataProxy[] getCachedProxies() { - Collection c = fProxyMap.values(); - return (CDataProxy[])c.toArray(new CDataProxy[c.size()]); + Collection c = fProxyMap.values(); + return c.toArray(new CDataProxy[c.size()]); } public CDataProxy getCachedProxy(String id) { - return (CDataProxy)fProxyMap.get(id); + return fProxyMap.get(id); } public void removeCachedProxy(String id) { - CDataProxy proxy = (CDataProxy)fProxyMap.get(id); + CDataProxy proxy = fProxyMap.get(id); removeCachedProxy(proxy); } - public Map getCachedProxiesMap() { - return (Map)fProxyMap.clone(); + public Map getCachedProxiesMap() { + return (Map)fProxyMap.clone(); } public CDataProxy getCachedProxy(CDataObject data) { diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ICProjectDescriptionStorageType.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ICProjectDescriptionStorageType.java new file mode 100644 index 00000000000..4c80d77224a --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ICProjectDescriptionStorageType.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom Corp. 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.settings.model; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.osgi.framework.Version; + +/** + * Interface defining an ICProjectDescriptionStorageType + * used as a factory for creating project description storages + * for a give project + */ +public interface ICProjectDescriptionStorageType { + /** The file name in which the storage type and version are stored */ + public static final String STORAGE_FILE_NAME = ".cproject"; //$NON-NLS-1$ + /** The document version attribute */ + public static final String STORAGE_VERSION_NAME = "fileVersion"; //$NON-NLS-1$ + /** The root element in a .cproject file */ + public static final String STORAGE_ROOT_ELEMENT_NAME = "cproject"; //$NON-NLS-1$ + /** The document's storage type id attribute in the root element */ + public static final String STORAGE_TYPE_ATTRIBUTE = "storage_type_id"; //$NON-NLS-1$ + + /** + * The type as defined in the CProjectDescriptionStorage extension point, wraps the + * implemented ICProjectDescriptionType to provide proxy object for use by CProjectDescriptionStorageManager + */ + public static final class CProjectDescriptionStorageTypeProxy implements ICProjectDescriptionStorageType { + private static final String ATTR_ID = "id"; //$NON-NLS-1$ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + private static final String ATTR_NAME = "name"; //$NON-NLS-1$ + private static final String ATTR_VERSION = "version"; //$NON-NLS-1$ + private static final String ATTR_MAX_VERSION = "max_version"; //$NON-NLS-1$ + private static final String ATTR_MIN_VERSION = "min_version"; //$NON-NLS-1$ + + public final String id; + public final String name; + public final ICProjectDescriptionStorageType storageType; + public final Version version; + public final Version max_version; + public final Version min_version; + + /** + * CProjectDescription Proxy Type. + * @param el + * @throws CoreException + * @throws IllegalArgumentException + */ + public CProjectDescriptionStorageTypeProxy(IConfigurationElement el) throws CoreException, IllegalArgumentException { + this (el.getNamespaceIdentifier() + "." + getString(el, ATTR_ID, null), //$NON-NLS-1$ + getString(el, ATTR_NAME, null), + (ICProjectDescriptionStorageType)el.createExecutableExtension(ATTR_CLASS), + getVersion(el, ATTR_VERSION, null), + getVersion(el, ATTR_MIN_VERSION, Version.emptyVersion), + getVersion(el, ATTR_MAX_VERSION, Version.emptyVersion)); + } + /** + * Constructor verifies that version is in the range (min_version, max_version] + * @param name + * @param storageType + * @param version + * @param min_version + * @param max_version + */ + public CProjectDescriptionStorageTypeProxy(String id, String name, ICProjectDescriptionStorageType storageType, Version version, + Version min_version, Version max_version) { + this.id = id; + this.name = name; + this.storageType = storageType; + this.version = version; + this.min_version = min_version; + this.max_version = max_version == Version.emptyVersion ? version : max_version; + if (min_version != Version.emptyVersion && version.compareTo(min_version) <= 0) + throw new IllegalArgumentException("CProjectDescriptionStorageType Version: " + version + + " must be > that min_version: " + min_version); + if (max_version != Version.emptyVersion && version.compareTo(max_version) > 0) + throw new IllegalArgumentException("CProjectDescriptionStorageType Version: " + version + + " must be < that max_version: " + max_version); + } + /** Indicates if this type is compatible with the provided version */ + public boolean isCompatible(Version version) { + if (version.compareTo(max_version) > 0) + return false; + if (version.compareTo(min_version) <= 0) + return false; + return true; + } + public boolean createsCProjectXMLFile() { + return storageType.createsCProjectXMLFile(); + } + public AbstractCProjectDescriptionStorage getProjectDescriptionStorage(CProjectDescriptionStorageTypeProxy type, IProject project, Version version) { + return storageType.getProjectDescriptionStorage(type, project, version); + } + + private static Version getVersion(IConfigurationElement element, String id, Version defaultValue) throws IllegalArgumentException{ + if (defaultValue == null) + return new Version(element.getAttribute(id)); + Version v = defaultValue; + try { + v = new Version(element.getAttribute(id)); + } catch (Exception e) { + // If an exception occurred return the default value + } + return v; + } + + private static String getString(IConfigurationElement element, String id, String defaultValue) throws IllegalArgumentException { + String val = element.getAttribute(id); + if (val != null) + return val; + if (defaultValue != null) + return defaultValue; + throw new IllegalArgumentException("Couldn't find value for extension attribute " + id); + } + } + + + /** + * Return a new storage instance to be for persisting / loading cproject descriptions + * from the passed in IProject + * @param type proxy which created this + * @param project - IProject + * @param version - Version number of the description as reported by the AbstractCProjectDescriptionStorage + * on last save + * @return AbstractCProjectDescriptionStorage + */ + public AbstractCProjectDescriptionStorage getProjectDescriptionStorage(CProjectDescriptionStorageTypeProxy type, IProject project, Version version); + + /** + * Method indicating whether this project storage type writes a .cproject file. + * + * If this method returns true then you must ensure that the .cproject file is an + * xml file with a {@link #STORAGE_VERSION_NAME} tag and {@link #STORAGE_TYPE_ATTRIBUTE} id + * in the {@link #STORAGE_ROOT_ELEMENT_NAME} e.g.: + *
+	 * <?xml version="1.0" encoding="UTF-8"?>
+	 * <?fileVersion 4.0.0?>
+	 * <cproject storageType="storage_type_id"> ....
+	 * </cproject>
+     * 
+ * + * If this method returns false, then the CProjectDescriptionStorageType creates + * a '.cproject' containing this data + * + * @return boolean indicating whether this storage type writes a (compatible) .cproject file + * @see CProjectDescriptionStorageTypeProxy + * + */ + public boolean createsCProjectXMLFile(); + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java index 24c654f4670..34a8b1b09bd 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java @@ -520,6 +520,15 @@ public class MultiConfigDescription extends MultiItemsHolder implements return true; } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.settings.model.ICSettingsStorage#setReadOnly(boolean, boolean) + */ + public void setReadOnly(boolean readOnly, boolean keepModify) { + for (ICConfigurationDescription cfg : fCfgs) + cfg.setReadOnly(readOnly, keepModify); + } + /* (non-Javadoc) * @see org.eclipse.cdt.core.settings.model.ICSettingObject#isValid() */ @@ -538,6 +547,14 @@ public class MultiConfigDescription extends MultiItemsHolder implements System.out.println("Bad multi access: MultiConfigDescription.getStorage()"); return null; } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.settings.model.ICSettingsStorage#getStorage(java.lang.String, boolean) + */ + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException { + System.out.println("Bad multi access: MultiConfigDescription.importStorage()"); + return null; + } /* (non-Javadoc) * @see org.eclipse.cdt.core.settings.model.ICSettingsStorage#removeStorage(java.lang.String) diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ResourceChangeHandler.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ResourceChangeHandler.java index 2544e08a0a8..c2689582119 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ResourceChangeHandler.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ResourceChangeHandler.java @@ -40,15 +40,23 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; +/** + * This resource change handler notices external changes to the cdt projects + * and associated project storage metadata files, as well as changes to + * source folders + * + * + * delegates parts of it's functionality to CProjectDescriptio + */ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements ISaveParticipant { CProjectDescriptionManager fMngr = CProjectDescriptionManager.getInstance(); class RcMoveHandler implements IResourceMoveHandler { - Map fProjDesMap = new HashMap(); - Set fRemovedProjSet = new HashSet(); + Map fProjDesMap = new HashMap(); + Set fRemovedProjSet = new HashSet(); public void handleProjectClose(IProject project) { - fMngr.setLoaddedDescription(project, null, true); + fMngr.projectClosedRemove(project); } private ICExclusionPatternPathEntry[] checkMove(IPath fromFullPath, IPath toFullPath, ICExclusionPatternPathEntry[] entries){ @@ -63,28 +71,17 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements return modified ? entries : null; } + @SuppressWarnings("fallthrough") public boolean handleResourceMove(IResource fromRc, IResource toRc) { boolean proceed = true; IProject fromProject = fromRc.getProject(); IProject toProject = toRc.getProject(); switch(toRc.getType()){ case IResource.PROJECT:{ - ICProjectDescription des = getProjectDescription(fromProject, false); + fMngr.projectMove(fromProject, toProject); fRemovedProjSet.add(fromProject); - if(des != null){ - ((CProjectDescription)des).updateProject(toProject); - synchronized (fMngr) { - fMngr.setLoaddedDescription(fromProject, null, true); - fMngr.setLoaddedDescription(toProject, des, true); - } - fProjDesMap.put(toProject, des); - ICConfigurationDescription[] cfgs = des.getConfigurations(); - for(int i = 0; i < cfgs.length; i++){ - cfgs[i].getConfigurationData(); - } - } } - break; + break; case IResource.FOLDER:{ IPath fromFullPath = fromRc.getFullPath(); IPath toFullPath = toRc.getFullPath(); @@ -155,7 +152,7 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements private ICProjectDescription getProjectDescription(IResource rc, boolean load){ IProject project = rc.getProject(); - ICProjectDescription des = (ICProjectDescription)fProjDesMap.get(project); + ICProjectDescription des = fProjDesMap.get(project); if(des == null && !fProjDesMap.containsKey(project)){ int flags = load ? 0 : CProjectDescriptionManager.GET_IF_LOADDED; flags |= CProjectDescriptionManager.INTERNAL_GET_IGNORE_CLOSE; @@ -171,13 +168,13 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements fProjDesMap.put(project, des); } - private List checkRemove(IPath rcFullPath, ICExclusionPatternPathEntry[] entries){ - List updatedList = null; + private List checkRemove(IPath rcFullPath, ICExclusionPatternPathEntry[] entries){ + List updatedList = null; int num = 0; for(int k = 0; k < entries.length; k++){ if(entries[k].getFullPath().equals(rcFullPath)){ if(updatedList == null){ - updatedList = new ArrayList(Arrays.asList(entries)); + updatedList = new ArrayList(Arrays.asList(entries)); } updatedList.remove(num); } else { @@ -187,12 +184,13 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements return updatedList; } + @SuppressWarnings("fallthrough") public boolean handleResourceRemove(IResource rc) { boolean proceed = true; IProject project = rc.getProject(); switch(rc.getType()){ case IResource.PROJECT: - fMngr.setLoaddedDescription(project, null, true); + fMngr.projectClosedRemove(project); fRemovedProjSet.add(project); proceed = false; break; @@ -205,11 +203,11 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements for(int i = 0; i < cfgDess.length; i++){ ICConfigurationDescription cfg = cfgDess[i]; ICExclusionPatternPathEntry[] entries = cfg.getSourceEntries(); - List updatedList = checkRemove(rcFullPath, entries); + List updatedList = checkRemove(rcFullPath, entries); if(updatedList != null){ try { - cfg.setSourceEntries((ICSourceEntry[])updatedList.toArray(new ICSourceEntry[updatedList.size()])); + cfg.setSourceEntries(updatedList.toArray(new ICSourceEntry[updatedList.size()])); } catch (WriteAccessException e) { CCorePlugin.log(e); } catch (CoreException e) { @@ -241,7 +239,9 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements try { cfgDess[i].removeResourceDescription(rcDescription); } catch (WriteAccessException e) { + CCorePlugin.log(e); } catch (CoreException e) { + CCorePlugin.log(e); } } } @@ -254,28 +254,28 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements } public void done() { - for(Iterator iter = fProjDesMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); + for(Iterator> iter = fProjDesMap.entrySet().iterator(); iter.hasNext();){ + Map.Entry entry = iter.next(); if(fRemovedProjSet.contains(entry.getKey())){ iter.remove(); } else { - ICProjectDescription des = (ICProjectDescription)entry.getValue(); + ICProjectDescription des = entry.getValue(); if(des != null && !des.isModified()) iter.remove(); } } - if(fProjDesMap.size() != 0){ - fMngr.runWspModification(new IWorkspaceRunnable(){ + if(!fProjDesMap.isEmpty()){ + CProjectDescriptionManager.runWspModification(new IWorkspaceRunnable(){ public void run(IProgressMonitor monitor) throws CoreException { - for(Iterator iter = fProjDesMap.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = (Map.Entry)iter.next(); - IProject project = (IProject)entry.getKey(); + for(Iterator> iter = fProjDesMap.entrySet().iterator(); iter.hasNext();){ + Map.Entry entry = iter.next(); + IProject project = entry.getKey(); if(!project.isOpen()) continue; - ICProjectDescription des = (ICProjectDescription)entry.getValue(); + ICProjectDescription des = entry.getValue(); try { fMngr.setProjectDescription(project, des); @@ -328,7 +328,7 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements } @Override - protected void doHahdleResourceMove(IResourceChangeEvent event, + protected void doHandleResourceMove(IResourceChangeEvent event, IResourceMoveHandler handler) { switch(event.getType()){ case IResourceChangeEvent.POST_CHANGE: @@ -348,34 +348,13 @@ public class ResourceChangeHandler extends ResourceChangeHandlerBase implements IResourceDelta child = children[k]; IResource rc = child.getResource(); if(rc.getType() != IResource.FILE) - continue; - - if(!CProjectDescriptionManager.STORAGE_FILE_NAME.equals(rc.getName())) - continue; - - //the .cproject file is changed - if((child.getKind() & IResourceDelta.REMOVED) == IResourceDelta.REMOVED){ - //project file does not exist or corrupted, remove - ((RcMoveHandler)handler).setProjectDescription(rc.getProject(), null); - continue; - } - - try { - CProjectDescription des = CProjectDescriptionManager.getInstance().checkExternalProjectFileModification(rc); - if(des != null){ - ((RcMoveHandler)handler).setProjectDescription(rc.getProject(), des); - } - } catch (CoreException e) { - CCorePlugin.log(e); - //project file does not exist or corrupted, remove - ((RcMoveHandler)handler).setProjectDescription(rc.getProject(), null); - } + continue; } } } break; } - super.doHahdleResourceMove(event, handler); + super.doHandleResourceMove(event, handler); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SetCProjectDescriptionOperation.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SetCProjectDescriptionOperation.java index c3bd75e9d31..5288fefc4a6 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SetCProjectDescriptionOperation.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SetCProjectDescriptionOperation.java @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; @@ -17,85 +18,103 @@ import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICDescriptionDelta; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.settings.model.ICSettingsStorage; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.internal.core.model.CModelOperation; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; +/** + * The operation which actually causes the CProjectDescription to be serialized + * + * This organizes the firing the {@link CProjectDescriptionEvent}s to all listeners + */ public class SetCProjectDescriptionOperation extends CModelOperation { - private CProjectDescription fSetDescription; - private int fFlags; + /** The ProjectDescription Storage being used for this project description */ + private final AbstractCProjectDescriptionStorage fPrjDescStorage; + private final CProjectDescription fSetDescription; + private final int fFlags; - SetCProjectDescriptionOperation(ICProject cProject, CProjectDescription description, int flags){ + /** + * Operation used for persisting the new CProjectDescription + * @param prjDescStorage + * @param cProject + * @param description + * @param flags + */ + public SetCProjectDescriptionOperation(AbstractCProjectDescriptionStorage prjDescStorage, ICProject cProject, CProjectDescription description, int flags){ super(cProject); + this.fPrjDescStorage = prjDescStorage; fFlags = flags; fSetDescription = description; } - + @Override protected void executeOperation() throws CModelException { CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); ICProject cProject = (ICProject)getElementToProcess(); final IProject project = cProject.getProject(); - - CProjectDescription fOldDescriptionCache = (CProjectDescription)mngr.getProjectDescription(project, false); - - CProjectDescriptionEvent event = mngr.createAboutToApplyEvent(fSetDescription, fOldDescriptionCache); - mngr.notifyListeners(event); + + ICProjectDescription fOldDescriptionCache = mngr.getProjectDescription(project, false); + + AbstractCProjectDescriptionStorage.fireAboutToApplyEvent(fSetDescription, fOldDescriptionCache); CProjectDescription fNewDescriptionCache = null; SettingsContext context = new SettingsContext(project); boolean modified = false; - + if(fSetDescription != null){ - InternalXmlStorageElement el = null; + ICStorageElement newEl = null; + ICSettingsStorage newStorage = null; try { - InternalXmlStorageElement base = (InternalXmlStorageElement)fSetDescription.getRootStorageElement(); - modified = base.isDirty(); - el = mngr.copyElement(base, false); - } catch (CoreException e2) { + ICStorageElement base = fSetDescription.getRootStorageElement(); + modified = fSetDescription.isModified(); +// el = base; + // FIXME JBB there is deep magic going on here. The project descriptions are being + // changed in non-obvious ways + newEl = fPrjDescStorage.copyElement(base, false); + newStorage = fPrjDescStorage.getStorageForElement(newEl); + } catch (CoreException e) { + CCorePlugin.log(e); } - + boolean creating = fOldDescriptionCache != null ? fOldDescriptionCache.isCdtProjectCreating() : true; if(creating) creating = fSetDescription.isCdtProjectCreating(); - + if(!fSetDescription.isValid() && (!mngr.isEmptyCreatingDescriptionAllowed() || !creating)) throw new CModelException(ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.17") + project.getName())); //$NON-NLS-1$ - - fNewDescriptionCache = new CProjectDescription(fSetDescription, true, el, creating); - + + fNewDescriptionCache = new CProjectDescription(fSetDescription, true, newStorage, newEl, creating); + boolean envStates[] = getEnvStates(fNewDescriptionCache); try { - mngr.setDescriptionApplying(project, fNewDescriptionCache); + fPrjDescStorage.setThreadLocalProjectDesc(fNewDescriptionCache); modified |= fNewDescriptionCache.applyDatas(context); } finally { - mngr.clearDescriptionApplying(project); + fPrjDescStorage.setThreadLocalProjectDesc(null); setEnvStates(fNewDescriptionCache, envStates); } } else { modified = fOldDescriptionCache != null; } - + ICDescriptionDelta delta = mngr.createDelta(fNewDescriptionCache, fOldDescriptionCache); mngr.checkRemovedConfigurations(delta); - - + + // Generate the c element deltas ICElementDelta cElementDeltas[] = mngr.generateCElementDeltas(cProject, delta); + for (ICElementDelta d : cElementDeltas) + addDelta(d); - if (cElementDeltas.length > 0) { - for (int i = 0; i < cElementDeltas.length; i++) { - addDelta(cElementDeltas[i]); - } - } - - mngr.setLoaddedDescription(project, fNewDescriptionCache, true); - if(fSetDescription != null) fSetDescription.switchToCachedAppliedData(fNewDescriptionCache); - + try { final IProjectDescription eDes = context.getEclipseProjectDescription(); if(mngr.checkHandleActiveCfgChange(fNewDescriptionCache, fOldDescriptionCache, eDes, new NullProgressMonitor())){ @@ -104,58 +123,83 @@ public class SetCProjectDescriptionOperation extends CModelOperation { } catch (CoreException e2) { CCorePlugin.log(e2); } - - event = mngr.createDataAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); - mngr.notifyListeners(event); - - cProject.close(); - + + // fNewDescriptionCache is still writable and may be written to at this point + AbstractCProjectDescriptionStorage.fireDataAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); + + cProject.close(); // Why? + // ExternalSettingsManager.getInstance().updateDepentents(delta); - + if(fNewDescriptionCache != null){ fNewDescriptionCache.doneApplying(); } - - event = mngr.createAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); + + // Set 'fSetProjectDescription' as the new read-only project description on the block + fPrjDescStorage.setCurrentDescription(fNewDescriptionCache, true); + + CProjectDescriptionEvent event = AbstractCProjectDescriptionStorage.createAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); mngr.notifyListeners(event); try { + IWorkspaceRunnable toRun = null; if(fNewDescriptionCache != null && !CProjectDescriptionManager.checkFlags(fFlags, ICProjectDescriptionManager.SET_NO_SERIALIZE)){ if(modified || isPersistentCoreSettingChanged(event)){ - context.addWorkspaceRunnable(mngr.createDesSerializationRunnable(fNewDescriptionCache)); + toRun = fPrjDescStorage.createDesSerializationRunnable(); + if (toRun != null) + context.addWorkspaceRunnable(toRun); } } - IWorkspaceRunnable toRun = context.createOperationRunnable(); - + toRun = context.createOperationRunnable(); + if(toRun != null) - mngr.runWspModification(toRun, new NullProgressMonitor()); + CProjectDescriptionManager.runWspModification(toRun, getSchedulingRule(), new NullProgressMonitor()); } catch (CoreException e) { throw new CModelException(e); } } - + + // Can't use project scoped rule see CProjectDescriptionBasicTests... +// /* +// * Instead of using the workspace scheduling rule, use a more refined project scoped rule. +// * This must contain the rule in CConfigBasedDescriptor.setApply(...) +// * (non-Javadoc) +// * @see org.eclipse.cdt.internal.core.model.CModelOperation#getSchedulingRule() +// */ +// @Override +// public ISchedulingRule getSchedulingRule() { +//// return null; +// return fPrjDescStorage.getProject(); +// } + private static boolean isPersistentCoreSettingChanged(CProjectDescriptionEvent event){ ICDescriptionDelta delta = event.getProjectDelta(); if(delta == null) return false; if(delta.getDeltaKind() != ICDescriptionDelta.CHANGED) return true; - + if(delta.getChildren().length != 0) return true; - - int flags = delta.getChangeFlags(); + + int flags = delta.getChangeFlags(); if(flags != 0 && flags != ICDescriptionDelta.ACTIVE_CFG) return true; - + return false; } - + @Override public boolean isReadOnly() { return false; } + /** + * Returns a boolean array corresponding to whether the environemnt is + * dirty on the configurations in the array returned by projDesc.getConfigurations() + * @param pd + * @return boolean[] indicating which configurations have a dirty environment + */ private boolean[] getEnvStates(CProjectDescription pd) { ICConfigurationDescription[] cfs = pd.getConfigurations(); boolean[] result = new boolean[cfs.length]; @@ -165,19 +209,28 @@ public class SetCProjectDescriptionOperation extends CModelOperation { CConfigurationSpecSettings ss = ((IInternalCCfgInfo)cfs[i]).getSpecSettings(); if (ss != null && ss.getEnvironment() != null) result[i] = ss.getEnvironment().isDirty(); - } catch (CoreException e) {}; + } catch (CoreException e) { + CCorePlugin.log(e); + } } } return result; } + /** + * Set + * @param pd + * @param data + */ private void setEnvStates(CProjectDescription pd, boolean[] data) { ICConfigurationDescription[] cfs = pd.getConfigurations(); if (cfs == null || data == null) return; for (int i=0; i fProjectDescription = new SoftReference(null); + /** The last modification stamp of the .cproject project description file */ + private volatile long projectModificaitonStamp = IResource.NULL_STAMP; + + /** A lock that is held during project description serialization + * This lock is also head during load to prevent a load overlapping + * with a concurrent reply (as resource locks aren't used for load...)*/ + private final ILock serializingLock = Job.getJobManager().newLock(); + + + @Override + public ICSettingsStorage getStorageForElement(ICStorageElement element) throws CoreException { + return new XmlStorage((InternalXmlStorageElement)element); + } + + @Override + public final ICProjectDescription getProjectDescription(int flags, IProgressMonitor monitor) throws CoreException { + ICProjectDescription des = null; + boolean write = checkFlags(flags, ICProjectDescriptionManager.GET_WRITABLE); + // Only 'load' if the caller hasn't explicitly requested currently loaded config + boolean load = !checkFlags(flags, ICProjectDescriptionManager.GET_IF_LOADDED); + // Create an empty configuration if the user has requested it + boolean empty = checkFlags(flags, ICProjectDescriptionManager.GET_EMPTY_PROJECT_DESCRIPTION); + boolean ignoreClose = checkFlags(flags, INTERNAL_GET_IGNORE_CLOSE); + boolean create = checkFlags(flags, ICProjectDescriptionManager.GET_CREATE_DESCRIPTION); + // set the PROJECT_CREATING flag on the project description + boolean creatingState = checkFlags(flags, ICProjectDescriptionManager.PROJECT_CREATING); + + SettingsContext context = null; + + des = super.getProjectDescription(flags, monitor); + + // If no thread local project description then check for the previous loaded one + // or load from the .cproject file + if (des == null) { + boolean released = false; + try { + // If the description is already loaded and has been modified externally, reload it + load |= checkExternalModification(); + + // Acquire the (de)serializing lock + serializingLock.acquire(); + + if (ignoreClose || project.isOpen()) + des = getLoadedDescription(); + + if (!empty && des == null && load && project.isOpen()) { + try { + des = loadProjectDescription(project); + } catch (CoreException e) { + // This isn't an issue as there may not be a project description + // file yet + } + if (des == null) { + // TODO: check if conversion needed + try { + context = new SettingsContext(project); + des = getConvertedDescription(context); + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + + if (des != null) { + if (setLoaddedDescriptionOnLoad(project, des)) { + // Current read-only description loaded, unlock the serializing lock + // (as saving conversion below will require acquiring resource scheduling rules...) + serializingLock.release(); + released = true; + + if (context != null) + saveConversion(project, context, (CProjectDescription) des, new NullProgressMonitor()); + fireLoadedEvent(des); + des = getLoadedDescription(); + } + } + } + } finally { + if (!released) + serializingLock.release(); + } + } + + // Only create a new empty configuration if the caller has requested an empty configuration + // or they're creating a configuration and there is no existing configuration found + if (empty || (des == null && create)) { + if (creatingState && des != null) + creatingState = des.isCdtProjectCreating(); + try { + InternalXmlStorageElement element = createStorage(project, ICProjectDescriptionStorageType.STORAGE_FILE_NAME, false, true, false); + return new CProjectDescription(project, new XmlStorage(element), element, false, creatingState); + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + + if (des != null && write) { + des = createWritableDescription((CProjectDescription) des); + } + return des; + } + + + /** + * Method to check whether the description has been modified externally. + * If so the current read-only descriptor is nullified. + * @return boolean indicating whether reload is needed + */ + protected synchronized boolean checkExternalModification() { + ICProjectDescription desc = getLoadedDescription(); + // If loaded, and we have cached the modification stamp, reload + if (desc != null && projectModificaitonStamp != IResource.NULL_STAMP) { + long currentModificationStamp = project.getFile(ICProjectDescriptionStorageType.STORAGE_FILE_NAME).getModificationStamp(); + if (projectModificaitonStamp < currentModificationStamp) { + setCurrentDescription(null, true); + projectModificaitonStamp = currentModificationStamp; + return true; + } + } + return false; + } + + /** + * Create a writable version of the description + * + * @param cache The base CProjectDescription on which the writable copy is to be created + * @return CProjectDescription of null on failure + */ + private CProjectDescription createWritableDescription(CProjectDescription cache) { + CProjectDescription des = null; + try { + InternalXmlStorageElement el = (InternalXmlStorageElement)cache.getRootStorageElement(); + el = copyElement(el, false); + + des = new CProjectDescription(cache, false, new XmlStorage(el), el, cache.isCdtProjectCreating()); + fireCopyCreatedEvent(des, cache); + } catch (CoreException e) { + CCorePlugin.log(e); + } + return des; + } + + /** + * @param project + * @param des + * @return + */ + private boolean setLoaddedDescriptionOnLoad(IProject project, ICProjectDescription des) { + des.setSessionProperty(LOAD_FLAG, Boolean.TRUE); + ICProjectDescription oldDes = getLoadedDescription(); + + setCurrentDescription(des, true); + + if (oldDes == null) + return true; + + return oldDes.getSessionProperty(LOAD_FLAG) == null; + } + + /* Sets the current read-only descriptions -- uses the write lock + * (non-Javadoc) + * @see org.eclipse.cdt.core.settings.model.AbstractCProjectDescriptionStorage#setCurrentDescription(org.eclipse.cdt.core.settings.model.ICProjectDescription, boolean) + */ + @Override + public boolean setCurrentDescription(ICProjectDescription des, boolean overwriteIfExists) { + if (!overwriteIfExists && fProjectDescription.get() != null) + return false; + + if (des != null) { + if (project.exists() && project.isOpen()) { + fProjectDescription = new SoftReference(des); + } else { + CCorePlugin.log(SettingsModelMessages.getString("CProjectDescriptionManager.16")); //$NON-NLS-1$ + } + } else { + fProjectDescription = new SoftReference(null); + } + return true; + } + + private Object[] loadProjectDescriptionFromOldstyleStorage() throws CoreException { + ICStorageElement rootEl = readOldCDTProjectFile(project); + if (rootEl != null) { + String ownerId = rootEl.getAttribute(OLD_PROJECT_OWNER_ID); + CProjectDescription des = (CProjectDescription) CProjectDescriptionManager.getInstance().createProjectDescription(project, false); + String id = CDataUtil.genId(CONVERTED_CFG_ID_PREFIX); + des.createConvertedConfiguration(id, CONVERTED_CFG_NAME, rootEl); + return new Object[] { ownerId, des }; + } + return null; + } + + /** + * Convert and Load a previous version of the Project Description + * + * @param project + * @param context + * @return + * @throws CoreException + */ + private ICProjectDescription getConvertedDescription(SettingsContext context) throws CoreException { + Object info[] = loadProjectDescriptionFromOldstyleStorage(); + CProjectDescription des = null; + String ownerId = null; + try { + if (info != null) { + ownerId = (String) info[0]; + des = (CProjectDescription) info[1]; + setThreadLocalProjectDesc(des); + des.setLoading(true); + } + + IProjectDescription eDes = context.getEclipseProjectDescription(); + + ICProjectConverter converter = CProjectDescriptionManager.getInstance().getConverter(project, ownerId, des); + if (converter != null) { + CProjectDescription convertedDes = (CProjectDescription) converter.convertProject(project, eDes, ownerId, des); + if (convertedDes != null) { + CProjectDescriptionManager.getInstance().checkHandleActiveCfgChange(convertedDes, null, eDes, new NullProgressMonitor()); + des = convertedDes; + } + } + + if (des != null && des.isValid()) { + // TODO: should be set via the CModel operation? + InternalXmlStorageElement el = null; + context.setEclipseProjectDescription(eDes); + + try { + el = copyElement(des.getRootStorageElement(), false); + } catch (CoreException e2) { + } + + des = new CProjectDescription(des, true, new XmlStorage(el), el, des.isCdtProjectCreating()); + setThreadLocalProjectDesc(des); + des.applyDatas(context); + des.doneApplying(); + } + } finally { + setThreadLocalProjectDesc(null); + if (des != null) + des.setLoading(false); + } + return des; + } + + private void saveConversion(final IProject proj, final SettingsContext context, CProjectDescription des, IProgressMonitor monitor) { + try { + context.addWorkspaceRunnable(createDesSerializationRunnable()); + } catch (CoreException e1) { + CCorePlugin.log(e1); + } + IWorkspaceRunnable toRun = context.createOperationRunnable(); + if (toRun != null) + CProjectDescriptionManager.runWspModification(toRun, monitor); + } + + /** + * Return the read-only ICProjectDescription + * in a thread-safe manner + */ + public ICProjectDescription getLoadedDescription() { + return fProjectDescription.get(); + } + + /** + * The internal method that actually causes the CProjectDescription to be created from an external storage. + * @param project + * @return the loaded ICProjectDescription + * @throws CoreException + */ + protected ICProjectDescription loadProjectDescription(IProject project) throws CoreException { + try { + // Ensure that there isn't a write to the project description occurring concurrently + serializingLock.acquire(); + + // Check if the description has already been loaded + if (!checkExternalModification() && getLoadedDescription() != null) + return getLoadedDescription(); + + // Don't log core exceptions caused by .cproject file not exists. Leave that to caller + InternalXmlStorageElement storage = createStorage(project, ICProjectDescriptionStorageType.STORAGE_FILE_NAME, true, false, false); + try { + // Update the modification stamp + projectModificaitonStamp = project.getFile(ICProjectDescriptionStorageType.STORAGE_FILE_NAME).getModificationStamp(); + CProjectDescription des = new CProjectDescription(project, new XmlStorage(storage), storage, true, false); + try { + setThreadLocalProjectDesc(des); + des.loadDatas(); + des.doneLoading(); + } finally { + setThreadLocalProjectDesc(null); + } + return des; + } catch (CoreException e) { + // XmlStorage constructor does sanity checking of the project xml storage element, ensure that errors here are logged + CCorePlugin.log(e); + throw e; + } + } finally { + serializingLock.release(); + } + } + + @Override + public IWorkspaceRunnable createDesSerializationRunnable() throws CoreException { + CProjectDescription des = (CProjectDescription)getLoadedDescription(); + if (des == null) // This won't happen because CModelOperation has a handle on the current read-only description + throw ExceptionFactory.createCoreException("No read-only Project Description found! Project: " + project.getName()); //$NON-NLS-1$ + final ICStorageElement element = des.getRootStorageElement(); + IWorkspaceRunnable r = new DesSerializationRunnable(des, element); + return r; + } + + /** + * Convert an Xml based ICStorageElement to an ByteArrayOutputStream + */ + private ByteArrayOutputStream write(ICStorageElement element) throws CoreException { + Document doc = ((InternalXmlStorageElement) element).fElement.getOwnerDocument(); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + DOMSource source = new DOMSource(doc); + StreamResult result = new StreamResult(stream); + transformer.transform(source, result); + + return stream; + } catch (TransformerConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (TransformerException e) { + throw ExceptionFactory.createCoreException(e); + } + } + + /** + * The method that *actually* performs the serialization of the settings... + * + * @param container - the folder in which file is to be serialized + * @param file - the name of the file to serialize the storage element tree into + * @param element - read-only ICStorageElement tree to be serialized (no need to lock) + * @throws CoreException + * @return long modification stamp of the file in the container + */ + protected long serialize(IContainer container, String file, ICStorageElement element) throws CoreException { + try { + final IFile projectFile = container.getFile(new Path(file)); + final ISchedulingRule rule = MultiRule.combine(new ISchedulingRule[] { + ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(projectFile), + ResourcesPlugin.getWorkspace().getRuleFactory().createRule(projectFile), + ResourcesPlugin.getWorkspace().getRuleFactory().deleteRule(projectFile) + }); + + String utfString; + ByteArrayOutputStream stream = null; + try { + // Get the ProjectDescription as a utf-8 string + stream = write(element); + utfString = stream.toString("UTF-8"); //$NON-NLS-1$ + } finally { + if (stream != null) + stream.close(); // Cleanup the stream + } + + try { + // Lock the projectFile + Job.getJobManager().beginRule(rule, null); + + // Ensure the file is writable + CProjectDescriptionStorageManager.ensureWritable(projectFile); + if (projectFile.exists()) { + try { + projectFile.setContents(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ + } catch (CoreException e) { + if (projectFile.getLocation().toFile().isHidden()) { + String os = System.getProperty("os.name"); //$NON-NLS-1$ + if (os != null && os.startsWith("Win")) { //$NON-NLS-1$ + projectFile.delete(true, null); + projectFile.create(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ + CCorePlugin.log(e.getLocalizedMessage() + "\n** Error occured because of file status ." + //$NON-NLS-1$ + "\n** This status is disabled now, to allow writing."); //$NON-NLS-1$ + } else + throw (e); + } else + throw (e); + } + } else { + projectFile.create(new ByteArrayInputStream(utfString.getBytes("UTF-8")), IResource.FORCE, new NullProgressMonitor()); //$NON-NLS-1$ + } + return projectFile.getModificationStamp(); + } finally { + Job.getJobManager().endRule(rule); + } + } catch (IOException e) { + throw ExceptionFactory.createCoreException(e); + } + } + + private ICStorageElement readOldCDTProjectFile(IProject project) throws CoreException { + ICStorageElement storage = null; + try { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = null; + InputStream stream = getSharedProperty(project, OLD_CDTPROJECT_FILE_NAME); + if (stream != null) { + doc = builder.parse(stream); + NodeList nodeList = doc.getElementsByTagName(OLD_PROJECT_DESCRIPTION); + + if (nodeList != null && nodeList.getLength() > 0) { + Node node = nodeList.item(0); + storage = new InternalXmlStorageElement((Element) node, false); + } + } + } catch (ParserConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (SAXException e) { + throw ExceptionFactory.createCoreException(e); + } catch (IOException e) { + throw ExceptionFactory.createCoreException(e); + } + return storage; + } + + /** + * This method returns an ICStorageElement from a given Xml file filename in the container + * container + * + * @param container + * @param fileName + * @param reCreate + * @param createEmptyIfNotFound + * @param readOnly + * @return InternalXmlStorageElement representing the particular storage + * @throws CoreException + */ + protected InternalXmlStorageElement createStorage(IContainer container, String fileName, boolean reCreate, boolean createEmptyIfNotFound, boolean readOnly) throws CoreException{ + try { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = null; + Element element = null; + InputStream stream = null; + if(reCreate){ + try{ + stream = getSharedProperty(container, fileName); + if(stream != null){ + doc = builder.parse(stream); + + // Get the first element in the project file + Node rootElement = doc.getFirstChild(); + + if (rootElement.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE) { + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.7")); //$NON-NLS-1$ + } else { + // Make sure that the version is compatible with the manager + String fileVersion = rootElement.getNodeValue(); + Version version = new Version(fileVersion); + if (getVersion().compareTo(version) < 0) { + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.8")); //$NON-NLS-1$ + } + } + + // Now get the project root element (there should be only one) + NodeList nodes = doc.getElementsByTagName(ICProjectDescriptionStorageType.STORAGE_ROOT_ELEMENT_NAME); + if (nodes.getLength() == 0) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.9")); //$NON-NLS-1$ + Node node = nodes.item(0); + if(node.getNodeType() != Node.ELEMENT_NODE) + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.10")); //$NON-NLS-1$ + element = (Element)node; + } else if(!createEmptyIfNotFound){ + throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.11") + fileName); //$NON-NLS-1$ + } + } catch (FactoryConfigurationError e) { + if(!createEmptyIfNotFound) + throw ExceptionFactory.createCoreException(e.getLocalizedMessage()); + } catch (SAXException e) { + if(!createEmptyIfNotFound) + throw ExceptionFactory.createCoreException(e); + } catch (IOException e) { + if(!createEmptyIfNotFound) + throw ExceptionFactory.createCoreException(e); + } finally { + if(stream != null){ + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + + if(element == null) { + doc = builder.newDocument(); + ProcessingInstruction instruction = doc.createProcessingInstruction(ICProjectDescriptionStorageType.STORAGE_VERSION_NAME, getVersion().toString()); + doc.appendChild(instruction); + element = doc.createElement(ICProjectDescriptionStorageType.STORAGE_ROOT_ELEMENT_NAME); + element.setAttribute(ICProjectDescriptionStorageType.STORAGE_TYPE_ATTRIBUTE, getStorageTypeId()); + doc.appendChild(element); + } + + return new InternalXmlStorageElement(element, null, false, readOnly); + } catch (ParserConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } + } + + /** + * @return the maximum version supported by this description storage + */ + protected Version getVersion() { + return STORAGE_DESCRIPTION_VERSION; + } + + /** + * @return Return the storage type id for this storage + */ + protected String getStorageTypeId() { + return STORAGE_TYPE_ID; + } + + /** + * Return an input stream for the given file in the provided container + * @param container + * @param key + * @return InputStream + * @throws CoreException on failure + */ + public InputStream getSharedProperty(IContainer container, String key) throws CoreException { + InputStream stream = null; + final IFile rscFile = container.getFile(new Path(key)); + if (rscFile.exists()) { + try { + stream = rscFile.getContents(true); + } catch (CoreException e) { + // try refreshing + final Throwable[] t = new Throwable[1]; + Job job = CProjectDescriptionManager.runWspModification(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + try { + rscFile.refreshLocal(IResource.DEPTH_ZERO, null); + } catch (Exception e) { + t[0] = e; + } + } + }, rscFile, new NullProgressMonitor()); + + // if refresh was performed "inline" without job scheduled + if (job == null) { + // if no exceptions occured + if (t[0] == null) { + // try get contents + stream = rscFile.getContents(); + } else { + // refresh failed + if (t[0] instanceof CoreException) + throw (CoreException) t[0]; + throw e; + } + } else { + throw e; + } + } + } else { + // FIXME JBB remove? + // when a project is imported, we get a first delta for the addition + // of the .project, but the .classpath is not accessible + // so default to using java.io.File + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258 + URI location = rscFile.getLocationURI(); + if (location != null) { + IFileStore file = EFS.getStore(location); + IFileInfo info = null; + + if (file != null) { + info = file.fetchInfo(); + if (info != null && info.exists()) + stream = file.openInputStream(EFS.NONE, null); + } + } + } + return stream; + } + + @Override + public void projectCloseRemove() { + super.projectCloseRemove(); + setCurrentDescription(null, true); + } + + @Override + public void projectMove(IProject newProject) { + super.projectMove(newProject); + + // FIXME JBB From ResourceChangeHandler. + // Why do the project description and configurations need to know + // their project? They should ask their ProjectDescriptionStorage + CProjectDescription desc = (CProjectDescription)fProjectDescription.get(); + if (desc != null) { + desc.updateProject(newProject); + } + } + + /** + * Return an Xml element copy based on a passed in InternalXmlStorageElement + * + * @param el + * @return Xml element based on a passed in xml ICStorageElement (InternalXmlStorageElement) + * @throws CoreException + */ + public Element createXmlElementCopy(InternalXmlStorageElement el) throws CoreException { + try { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.newDocument(); + Element newXmlEl = null; + if (el.fElement.getParentNode().getNodeType() == Node.DOCUMENT_NODE) { + Document baseDoc = el.fElement.getOwnerDocument(); + NodeList list = baseDoc.getChildNodes(); + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + node = importAddNode(doc, node); + if (node.getNodeType() == Node.ELEMENT_NODE && newXmlEl == null) { + newXmlEl = (Element) node; + } + } + + } else { + newXmlEl = (Element) importAddNode(doc, el.fElement); + } + return newXmlEl; + } catch (ParserConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (FactoryConfigurationError e) { + throw ExceptionFactory.createCoreException(e); + } + + } + + @Override + public InternalXmlStorageElement copyElement(ICStorageElement el, boolean readOnly) throws CoreException { + InternalXmlStorageElement internalEl = (InternalXmlStorageElement)el; + Element newXmlEl = createXmlElementCopy(internalEl); + return new InternalXmlStorageElement(newXmlEl, internalEl.getParent(), internalEl.getAttributeFilters(), internalEl.getChildFilters(), readOnly); + } + + private Node importAddNode(Document doc, Node node) { + if (node.getOwnerDocument().equals(doc)) { + node = node.cloneNode(true); + } else { + node = doc.importNode(node, true); + } + + return doc.appendChild(node); + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorageFactory.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorageFactory.java new file mode 100644 index 00000000000..f6f4be97daf --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorageFactory.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.internal.core.settings.model.xml; + +import org.eclipse.cdt.internal.core.settings.model.AbstractCProjectDescriptionStorage; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType; +import org.eclipse.core.resources.IProject; +import org.osgi.framework.Version; + +/** + * Concrete implementation of ICProjectDescriptionStorageType + * for instantiating XmlProjectDescriptionStorage + */ +public class XmlProjectDescriptionStorageFactory implements ICProjectDescriptionStorageType { + + public AbstractCProjectDescriptionStorage getProjectDescriptionStorage(CProjectDescriptionStorageTypeProxy type, IProject project, Version version) { + return new XmlProjectDescriptionStorage(type, project, version); + } + + public boolean createsCProjectXMLFile() { + return true; + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorage.java new file mode 100644 index 00000000000..2c505acdae9 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorage.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2007 Intel 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: + * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.internal.core.settings.model.xml; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.cdt.core.settings.model.ICSettingsStorage; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; +import org.eclipse.core.runtime.CoreException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Concrete implementation of ICSettingsStorage backed by an XML document + * + * ICStorageElements are stored in the tree under a storageModule element. + * (This class was previously called CStorage) + * TODO JBB Make this independent of the Xml Element + */ +public class XmlStorage implements ICSettingsStorage { + public static final String MODULE_ELEMENT_NAME = "storageModule"; //$NON-NLS-1$ + public static final String MODULE_ID_ATTRIBUTE = "moduleId"; //$NON-NLS-1$ + public Element fElement; + private Map fStorageElementMap = new HashMap(); + private boolean fChildrenInited; + private boolean fIsReadOnly; + private boolean fIsDirty; + + public XmlStorage(Element element, boolean isReadOnly){ + fElement = element; + fIsReadOnly = isReadOnly; + } + + public XmlStorage(InternalXmlStorageElement element) throws CoreException { + fElement = element.fElement; + fIsReadOnly = element.isReadOnly(); + element.storageCreated(this); + sanityCheck(element); + } + + /** + * Check that the XmlStorageElement on which this SettingsStorage + * is based doesn't have any attributes, values or children which + * are invalid for a settings storage. + * @param element + * @throws CoreException + */ + public void sanityCheck(ICStorageElement element) throws CoreException { + if (element.getValue() != null && element.getValue().trim().length() > 0) + throw ExceptionFactory.createCoreException("XmlStorage '" + element.getName() + "' has unexpected child Value: " + element.getValue()); + for (ICStorageElement child : element.getChildren()) { + if (!MODULE_ELEMENT_NAME.equals(child.getName())) + throw ExceptionFactory.createCoreException("XmlStorage '" + element.getName() + "' has unexpected child element: " + child.getName()); + if (child.getAttribute(MODULE_ID_ATTRIBUTE) == null) + throw ExceptionFactory.createCoreException("XmlStorage '" + element.getName() + "' has storageModule child without moduleId"); + } + } + + public boolean isReadOnly(){ + return fIsReadOnly; + } + + /** + * Initialise the set of storageModules of this XmlStorage + */ + private void initChildren(){ + if(fChildrenInited) + return; + fChildrenInited = true; + + NodeList children = fElement.getChildNodes(); + int size = children.getLength(); + for(int i = 0; i < size; i++){ + Node node = children.item(i); + if(node.getNodeType() != Node.ELEMENT_NODE) + continue; + if(!MODULE_ELEMENT_NAME.equals(node.getNodeName())) + continue; + + Element element = (Element)node; + String moduleId = element.getAttribute(MODULE_ID_ATTRIBUTE).trim(); + if(moduleId.length() == 0) + continue; + + createAddStorageElement(moduleId, element); + } + } + + private InternalXmlStorageElement createAddStorageElement(String id, Element element){ + InternalXmlStorageElement se = createStorageElement(element, fIsReadOnly); + fStorageElementMap.put(id, se); + return se; + } + + public static InternalXmlStorageElement createStorageElement(Element el, boolean isReadOnly){ + return new InternalXmlStorageElement(el, null, new String[]{MODULE_ID_ATTRIBUTE}, null, isReadOnly); + } + +// public ICStorageElement getStorage(String id){ +// return getStorage(id, true); +// } + + + public boolean containsStorage(String id) throws CoreException { + return getStorage(id, false) != null; + } + + public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException { + if(fIsReadOnly) + throw ExceptionFactory.createIsReadOnlyException(); + + // Remove existing storage with this ID + removeStorage(id); + + // Create the storage element for import + Document thisDoc = fElement.getOwnerDocument(); + Element newEl = thisDoc.createElement(MODULE_ELEMENT_NAME); + + fIsDirty = true; + + if (el instanceof XmlStorageElement) { + // If we're importing an XmlStorageElement use XML methods + XmlStorageElement xmlStEl = (XmlStorageElement)el; + Element xmlEl = xmlStEl.fElement; + Document otherDoc = xmlEl.getOwnerDocument(); + if(!thisDoc.equals(otherDoc)){ + xmlEl = (Element)thisDoc.importNode(xmlEl, true); + } + + NodeList nl = xmlEl.getChildNodes(); + for(int i = 0; i < nl.getLength(); i++){ + Node child = nl.item(i).cloneNode(true); + newEl.appendChild(child); + } + newEl = (Element)fElement.appendChild(newEl); + newEl.setAttribute(MODULE_ID_ATTRIBUTE, id); + + return createAddStorageElement(id, newEl); + } else { + // Otherwise importing generic ICStorageElement + ICStorageElement storageEl = getStorage(id, true); + for (String attrName: el.getAttributeNames()) + storageEl.setAttribute(attrName, el.getAttribute(attrName)); + for (ICStorageElement child: el.getChildren()) + storageEl.importChild(child); + return storageEl; + } + } + + public ICStorageElement getStorage(String id, boolean create){ + initChildren(); + + InternalXmlStorageElement se = fStorageElementMap.get(id); + if(se == null && create){ +// if(fIsReadOnly) +// throw ExceptionFactory.createIsReadOnlyException(); + + fIsDirty = true; + Document doc = fElement.getOwnerDocument(); + Element child = createStorageXmlElement(doc, id); + fElement.appendChild(child); + se = createAddStorageElement(id, child); + } + return se; + } + + public static Element createStorageXmlElement(Document doc, String storageId){ + Element child = doc.createElement(MODULE_ELEMENT_NAME); + child.setAttribute(MODULE_ID_ATTRIBUTE, storageId); + + return child; + } + + public void removeStorage(String id){ + initChildren(); + InternalXmlStorageElement se = fStorageElementMap.remove(id); + + if(se != null){ + if(fIsReadOnly) + throw ExceptionFactory.createIsReadOnlyException(); + + fIsDirty = true; + Node nextSibling = se.fElement.getNextSibling(); + fElement.removeChild(se.fElement); + if (nextSibling != null && nextSibling.getNodeType() == Node.TEXT_NODE) { + String value = nextSibling.getNodeValue(); + if (value != null && value.trim().length() == 0) { + // remove whitespace + fElement.removeChild(nextSibling); + } + } + } + } + + public boolean isModified(){ + if(fIsDirty) + return true; + + for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ + InternalXmlStorageElement el = iter.next(); + if(el.isModified()) + return true; + } + + return false; + } + + public void setReadOnly(boolean readOnly, boolean keepModify){ + fIsReadOnly = readOnly; + fIsDirty &= keepModify; + for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ + InternalXmlStorageElement el = iter.next(); + el.setReadOnly(readOnly, keepModify); + } + } + + public void setDirty(boolean isDirty){ + fIsDirty = isDirty; + + if(!fIsDirty){ + for(Iterator iter = fStorageElementMap.values().iterator(); iter.hasNext();){ + InternalXmlStorageElement el = iter.next(); + el.setDirty(false); + } + } + } + + public void save() throws CoreException { + throw new UnsupportedOperationException(); + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/XmlStorageElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorageElement.java similarity index 58% rename from core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/XmlStorageElement.java rename to core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorageElement.java index d1f54695721..6d5cade07c9 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/XmlStorageElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlStorageElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Intel Corporation and others. + * Copyright (c) 2007, 2008 Intel 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 @@ -7,16 +7,31 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ -package org.eclipse.cdt.core.settings.model.util; +package org.eclipse.cdt.internal.core.settings.model.xml; +import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.cdt.core.settings.model.ICSettingsStorage; import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; +import org.eclipse.core.runtime.CoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -25,60 +40,47 @@ import org.w3c.dom.NodeList; import org.w3c.dom.Text; public class XmlStorageElement implements ICStorageElement { + + protected static final String[] emptyStringList = new String[0]; - Element fElement; + public Element fElement; private ICStorageElement fParent; - private List fChildList = new ArrayList(); + protected List fChildList = new ArrayList(); private boolean fChildrenCreated; private String[] fAttributeFilters; private String[] fChildFilters; - private boolean fParentRefAlowed; public XmlStorageElement(Element element){ this(element, null, false); } public XmlStorageElement(Element element, ICStorageElement parent, boolean alowReferencingParent){ - this(element, parent, alowReferencingParent, null, null); + this(element, parent, null, null); } public XmlStorageElement(Element element, ICStorageElement parent, - boolean alowReferencingParent, String[] attributeFilters, String[] childFilters){ fElement = element; fParent = parent; - fParentRefAlowed = alowReferencingParent; if(attributeFilters != null && attributeFilters.length != 0) - fAttributeFilters = (String[])attributeFilters.clone(); + fAttributeFilters = attributeFilters.clone(); if(childFilters != null && childFilters.length != 0) - fChildFilters = (String[])childFilters.clone(); + fChildFilters = childFilters.clone(); } -// public String[] getAttributeFilters(){ -// if(fAttributeFilters != null) -// return (String[])fAttributeFilters.clone(); -// return null; -// } - -// public String[] getChildFilters(){ -// if(fChildFilters != null) -// return (String[])fChildFilters.clone(); -// return null; -// } -// -// public boolean isParentRefAlowed(){ -// return fParentRefAlowed; -// } - + /** + * Create ICStorageElement children from Xml tree + */ private void createChildren(){ if(fChildrenCreated) return; - + fChildrenCreated = true; + fChildList.clear(); NodeList list = fElement.getChildNodes(); int size = list.getLength(); for(int i = 0; i < size; i++){ @@ -103,14 +105,14 @@ public class XmlStorageElement implements ICStorageElement { boolean alowReferencingParent, String[] attributeFilters, String[] childFilters){ - return new XmlStorageElement(element, this, alowReferencingParent, attributeFilters, childFilters); + return new XmlStorageElement(element, this, attributeFilters, childFilters); } public ICStorageElement[] getChildren() { return getChildren(XmlStorageElement.class); } - protected ICStorageElement[] getChildren(Class clazz){ + protected ICStorageElement[] getChildren(Class clazz){ return getChildren(clazz, true); } @@ -118,18 +120,32 @@ public class XmlStorageElement implements ICStorageElement { return getChildren(XmlStorageElement.class, load); } - protected ICStorageElement[] getChildren(Class clazz, boolean load){ + protected ICStorageElement[] getChildren(Class clazz, boolean load){ if(load) createChildren(); ICStorageElement[] children = (ICStorageElement[])java.lang.reflect.Array.newInstance( clazz, fChildList.size()); - return (ICStorageElement[])fChildList.toArray(children); + return fChildList.toArray(children); + } + + public ICStorageElement[] getChildrenByName(String name) { + createChildren(); + ArrayList children = new ArrayList(); + for (ICStorageElement child : fChildList) + if (name.equals(child.getName())) + children.add(child); + return children.toArray(new ICStorageElement[children.size()]); + } + + public boolean hasChildren() { + createChildren(); + return !fChildList.isEmpty(); } public ICStorageElement getParent() { - return fParentRefAlowed ? fParent : null; + return fParent; } public String getAttribute(String name) { @@ -138,6 +154,10 @@ public class XmlStorageElement implements ICStorageElement { return null; } + public boolean hasAttribute(String name) { + return fElement.hasAttribute(name); + } + private boolean isPropertyAlowed(String name){ if(fAttributeFilters != null){ return checkString(name, fAttributeFilters); @@ -162,27 +182,22 @@ public class XmlStorageElement implements ICStorageElement { return true; } -// protected void childRemoved(ICStorageElement child) { -// fChildList.remove(child); -// } - - protected void removed(){ -// fElement.getParentNode().removeChild(fElement); - fElement = null; -// if(fParent != null) -// ((XmlStorageElement)fParent).childRemoved(this); - } - - public void removeChild(ICStorageElement el) { if(el instanceof XmlStorageElement){ ICStorageElement[] children = getChildren(); for(int i = 0; i < children.length; i++){ if(children[i] == el){ XmlStorageElement xmlEl = (XmlStorageElement)el; + Node nextSibling = xmlEl.fElement.getNextSibling(); fElement.removeChild(xmlEl.fElement); + if (nextSibling != null && nextSibling.getNodeType() == Node.TEXT_NODE) { + String value = nextSibling.getNodeValue(); + if (value != null && value.trim().length() == 0) { + // remove whitespace + fElement.removeChild(nextSibling); + } + } fChildList.remove(el); - xmlEl.removed(); } } } @@ -202,26 +217,28 @@ public class XmlStorageElement implements ICStorageElement { public void clear(){ createChildren(); - ICStorageElement children[] = (ICStorageElement[])fChildList.toArray(new ICStorageElement[fChildList.size()]); + ICStorageElement children[] = fChildList.toArray(new ICStorageElement[fChildList.size()]); for(int i = 0; i < children.length; i++){ removeChild(children[i]); } - + NamedNodeMap map = fElement.getAttributes(); for(int i = 0; i < map.getLength(); i++){ Node attr = map.item(i); if(isPropertyAlowed(attr.getNodeName())) map.removeNamedItem(attr.getNodeName()); } - - NodeList list = fElement.getChildNodes(); - for(int i = 0; i < list.getLength(); i++){ - Node node = list.item(i); + + Node node = fElement.getFirstChild(); + while (node != null) { + Node nextChildNode = node.getNextSibling(); if(node.getNodeType() == Node.TEXT_NODE) fElement.removeChild(node); + // update the pointer + node = nextChildNode; } } - + public ICStorageElement createChild(String name, boolean alowReferencingParent, String[] attributeFilters, @@ -304,37 +321,29 @@ public class XmlStorageElement implements ICStorageElement { xmlEl = (Element)fElement.appendChild(xmlEl); return createAddChild(xmlEl, alowReferencingParent, attributeFilters, childFilters); } else { + // FIXME JBB allow import of other types of ICStorageElement throw new UnsupportedOperationException(); } } public String[] getAttributeFilters(){ if(fAttributeFilters != null) - return (String[])fAttributeFilters.clone(); - return new String[0]; + return fAttributeFilters.clone(); + return emptyStringList; } public String[] getChildFilters(){ if(fChildFilters != null) - return (String[])fChildFilters.clone(); - return new String[0]; + return fChildFilters.clone(); + return emptyStringList; } - public boolean isParentRefAlowed(){ - return fParentRefAlowed; - } - - public boolean matches(ICStorageElement el){ + public boolean equals(ICStorageElement el){ if(!getName().equals(el.getName())) return false; - String value = getValue(); - if(value == null){ - if(el.getValue() != null) - return false; - } else if(!value.equals(el.getValue())) + if (!valuesMatch(getValue(), el.getValue())) return false; - String[] attrs = getAttributeNames(); String[] otherAttrs = el.getAttributeNames(); @@ -342,7 +351,7 @@ public class XmlStorageElement implements ICStorageElement { return false; if(attrs.length != 0){ - Set set = new HashSet(Arrays.asList(attrs)); + Set set = new HashSet(Arrays.asList(attrs)); set.removeAll(Arrays.asList(otherAttrs)); if(set.size() != 0) return false; @@ -363,7 +372,7 @@ public class XmlStorageElement implements ICStorageElement { if(children.length != 0){ for(int i = 0; i < children.length; i++){ - if(!children[i].matches(otherChildren[i])) + if(!children[i].equals(otherChildren[i])) return false; } } @@ -371,17 +380,103 @@ public class XmlStorageElement implements ICStorageElement { return true; } + private static boolean valuesMatch(String value, String other) { + if(value == null) { + return other == null || other.trim().length() == 0; + } else if (other == null) { + return value.trim().length() == 0; + } else { + return value.trim().equals(other.trim()); + } + } + public String[] getAttributeNames() { NamedNodeMap nodeMap = fElement.getAttributes(); int length = nodeMap.getLength(); - List list = new ArrayList(length); + List list = new ArrayList(length); for(int i = 0; i < length; i++){ Node node = nodeMap.item(i); String name = node.getNodeName(); if(isPropertyAlowed(name)) list.add(name); } - return (String[])list.toArray(new String[list.size()]); + return list.toArray(new String[list.size()]); + } + + public ICStorageElement createCopy() throws UnsupportedOperationException, CoreException { + Element newEl = createXmlElementCopy(); + return new XmlStorageElement(newEl, null, fAttributeFilters, fChildFilters); + } + + protected Element createXmlElementCopy() throws CoreException { + + try { + Element newXmlEl = null; + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.newDocument(); + if(fElement.getParentNode().getNodeType() == Node.DOCUMENT_NODE){ + Document baseDoc = fElement.getOwnerDocument(); + NodeList list = baseDoc.getChildNodes(); + for(int i = 0; i < list.getLength(); i++){ + Node node = list.item(i); + node = importAddNode(doc, node); + if(node.getNodeType() == Node.ELEMENT_NODE && newXmlEl == null){ + newXmlEl = (Element)node; + } + } + + } else { + newXmlEl = (Element)importAddNode(doc, fElement); + } +// Document baseDoc = el.fElement.getOwnerDocument(); +// Element baseEl = baseDoc.getDocumentElement(); +// Element newXmlEl = (Element)doc.importNode(baseEl, true); + + +// doc.appendChild(newXmlEl); + return newXmlEl; + } catch (ParserConfigurationException e) { + throw ExceptionFactory.createCoreException(e); + } catch (FactoryConfigurationError e) { + throw ExceptionFactory.createCoreException(e); + } + } + + private Node importAddNode(Document doc, Node node){ + if(node.getOwnerDocument().equals(doc)){ + node = node.cloneNode(true); + } else { + node = doc.importNode(node, true); + } + + return doc.appendChild(node); + } + + public ICSettingsStorage createSettingStorage(boolean readOnly) throws CoreException, UnsupportedOperationException { + return new XmlStorage(fElement, readOnly); + } + + /* + * toString() outputs XML tree -- useful for debugging + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + + DOMSource source = new DOMSource(fElement); + StreamResult result = new StreamResult(stream); + transformer.transform(source, result); + builder.append(stream.toString()); + + } catch (Exception e){ + return fElement.toString(); + } + + return builder.toString(); } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2.java new file mode 100644 index 00000000000..713fc467c71 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.settings.model.xml2; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionStorageManager; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType.CProjectDescriptionStorageTypeProxy; +import org.eclipse.cdt.internal.core.settings.model.xml.InternalXmlStorageElement; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorage; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceProxy; +import org.eclipse.core.resources.IResourceProxyVisitor; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.osgi.framework.Version; +import org.w3c.dom.Element; + +/** + * This class extends XmlProjectDescriptionStroage to provide the following + * functionality: + * - Configuration Description storage modules are persisted in separate XML + * files stored under .csettings in the project root directory. They + * are linked into the main .cproject file via "externalCElementFile" element + * + * It is backwards compatible with XmlProjectDescriptionStorage. If it finds a file + * with Version less than 5.0, it will delegate to the previous XmlProjectDescriptionStorage + * + * This allows users to more easily version control their CDT project descriptions + * @see Bug 226457 + */ +public class XmlProjectDescriptionStorage2 extends XmlProjectDescriptionStorage { + /** Folder Name for storing Project specific configuration settings */ + static final String STORAGE_FOLDER_NAME = ".csettings"; //$NON-NLS-1$ + /** Element providing the name of the external C Element file */ + public static final String EXTERNAL_CELEMENT_KEY = "externalCElementFile"; //$NON-NLS-1$ + private static final String ID = "id"; //$NON-NLS-1$ + + /** Override the description version, we support version '5.0' files */ + @SuppressWarnings("hiding") + public static final Version STORAGE_DESCRIPTION_VERSION = new Version("5.0"); //$NON-NLS-1$ + /** The storage type id of this extended project description type */ + @SuppressWarnings("hiding") + public static final String STORAGE_TYPE_ID = CCorePlugin.PLUGIN_ID + ".XmlProjectDescriptionStorage2"; //$NON-NLS-1$ + + /** Map from storageModuleId to modification time stamp */ + Map modificationMap = Collections.synchronizedMap(new HashMap()); + + public XmlProjectDescriptionStorage2(CProjectDescriptionStorageTypeProxy type, IProject project, Version version) { + super(type, project, version); + } + + /* + * Check for external modification in the module files in the .csettings directory + * (non-Javadoc) + * @see org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage#checkExternalModification() + */ + @Override + protected synchronized boolean checkExternalModification() { + // Check if our parent thinks we need a reload + if (super.checkExternalModification()) + return true; + // If not currently loaded, then nothing to do + if (getLoadedDescription() == null) + return false; + final boolean[] needReload = new boolean[] { false }; + try { + project.getFolder(STORAGE_FOLDER_NAME).accept(new IResourceProxyVisitor() { + public boolean visit(IResourceProxy proxy) throws CoreException { + if (modificationMap.containsKey(proxy.getName())) + if (modificationMap.get(proxy.getName()) < proxy.getModificationStamp()) { + // There may be old storages in here, ensure we don't infinite reload... + modificationMap.put(proxy.getName(), proxy.getModificationStamp()); + setCurrentDescription(null, true); + needReload[0] = true; + } + return true; + } + }, IResource.NONE); + } catch (CoreException e) { + // STORAGE_FOLDER_NAME doesn't exist... or something went wrong during reload + if (project.getFolder(STORAGE_FOLDER_NAME).exists()) + CCorePlugin.log("XmlProjectDescriptionStorage2: Problem checking for external modification: " + e.getMessage()); + } + return needReload[0]; + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage#createStorage(org.eclipse.core.resources.IContainer, java.lang.String, boolean, boolean, boolean) + */ + @Override + protected final InternalXmlStorageElement createStorage(IContainer container, String fileName, boolean reCreate, boolean createEmptyIfNotFound, boolean readOnly) throws CoreException { + InternalXmlStorageElement el = super.createStorage(container, fileName, reCreate, createEmptyIfNotFound, readOnly); + + Queue nodesToCheck = new LinkedList(); + nodesToCheck.addAll(Arrays.asList(el.getChildren())); + while (!nodesToCheck.isEmpty()) { + ICStorageElement currEl = nodesToCheck.remove(); + + // If not a storageModule element or doesn't have EXTERNAL_CELEMENT_KEY, continue + if (!XmlStorage.MODULE_ELEMENT_NAME.equals(currEl.getName()) + || currEl.getAttribute(EXTERNAL_CELEMENT_KEY) == null) { + nodesToCheck.addAll(Arrays.asList(currEl.getChildren())); + continue; + } + + try { + // Found -- load the Document pointed to (allows multiple layers of indirection if need be) + InternalXmlStorageElement el2 = createStorage(project.getFolder(STORAGE_FOLDER_NAME), + currEl.getAttribute(EXTERNAL_CELEMENT_KEY), + reCreate, createEmptyIfNotFound, readOnly); + // Update the modification stamp + modificationMap.put(currEl.getAttribute(EXTERNAL_CELEMENT_KEY), project.getFolder(STORAGE_FOLDER_NAME).getFile(currEl.getAttribute(EXTERNAL_CELEMENT_KEY)).getModificationStamp()); + + ICStorageElement currParent = currEl.getParent(); + // Get the storageModule element in the new Document + ICStorageElement[] childStorages = el2.getChildrenByName(XmlStorage.MODULE_ELEMENT_NAME); + Assert.isTrue(childStorages.length == 1, "More than one storageModule in external Document!"); //$NON-NLS-1$ + + // Import the loaded element + currParent.importChild(childStorages[0]); + // Remove the placeholder + currParent.removeChild(currEl); + } catch (CoreException e) { + // If we're here there was a problem loading csettings when there is a .cproject file. + CCorePlugin.log(e); + throw e; + } + } + return el; + } + + /* + * Serialize the Project Description: + * - The .cproject file contains the root XML Elements. + * - We serialize the storageModule children of the CConfiguration elements (in the org.eclipse.cdt.settings module) + * to separate files in the .csettings directory to prevent unmanageably large XML deltas + * Return the modification stamp of the main .cproject file as our super method does + * (non-Javadoc) + * @see org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage#serialize(org.eclipse.core.resources.IContainer, java.lang.String, org.eclipse.cdt.core.settings.model.ICStorageElement) + */ + @Override + protected long serialize(IContainer container, String file, ICStorageElement element) throws CoreException { + // If the current loaded version is less than our version, then delegate to parent to handle persisting + // i.e. don't auto-upgrade + if (version.compareTo(type.version) < 0) + return super.serialize(container, file, element); + + // Copy the original passed in element, as we're going to re-write the children + InternalXmlStorageElement copy = copyElement(element, false); + // Map containing external CConfiguration elements to be serialized + Map externalStorageElements = new HashMap(); + + // Iterate through the initial children + for (ICStorageElement el : copy.getChildren()) { + // Only interested in root level org.eclipse.cdt.settings storageModules + if (!CProjectDescriptionManager.MODULE_ID.equals(el.getAttribute(XmlStorage.MODULE_ID_ATTRIBUTE))) + continue; + + Queue configStorages = new LinkedList(); + configStorages.addAll(Arrays.asList(el.getChildren())); + while (!configStorages.isEmpty()) { + InternalXmlStorageElement iEl = (InternalXmlStorageElement)configStorages.remove(); + + // If not a stroageModule element, the just add children ... + // e.g. configuration element... + if (iEl.getAttribute(XmlStorage.MODULE_ID_ATTRIBUTE) == null) { + configStorages.addAll(Arrays.asList(iEl.getChildren())); + continue; + } + + // Persist this storage Element fileName = configurationID_moduleID + String storageId = ((Element)iEl.fElement.getParentNode()).getAttribute(ID) + "_" //$NON-NLS-1$ + + iEl.getAttribute(XmlStorage.MODULE_ID_ATTRIBUTE); + + // create a dummy storage for the element held + InternalXmlStorageElement newEl = createStorage(project.getFolder(STORAGE_FOLDER_NAME), storageId, false, true, false); + newEl.importChild(copyElement(iEl, false)); + externalStorageElements.put(storageId, newEl); + + // Clear other attributes and children + iEl.clear(); + // Set the external c element key + iEl.fElement.setAttribute(EXTERNAL_CELEMENT_KEY, storageId); + } + } + + // Serialize the Root XML document Element (.cproject) + long cproject_mod_time = super.serialize(project, ICProjectDescriptionStorageType.STORAGE_FILE_NAME, copy); + + // Check that the .csettings directory exists and is writable + IFolder csettings = project.getFolder(STORAGE_FOLDER_NAME); + try { + CProjectDescriptionStorageManager.ensureWritable(csettings); + if (!csettings.exists()) + csettings.create(true, true, new NullProgressMonitor()); + } catch (CoreException e) { + if (!csettings.exists()) + throw e; + } + + // Serialize all the external elements + for (Map.Entry e : externalStorageElements.entrySet()) + modificationMap.put(e.getKey(), super.serialize(csettings, e.getKey(), e.getValue())); + + return cproject_mod_time; + } + + @Override + protected Version getVersion() { + return STORAGE_DESCRIPTION_VERSION; + } + + @Override + protected String getStorageTypeId() { + return STORAGE_TYPE_ID; + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2Factory.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2Factory.java new file mode 100644 index 00000000000..c2dd063c10e --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml2/XmlProjectDescriptionStorage2Factory.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2008 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.settings.model.xml2; + +import org.eclipse.cdt.internal.core.settings.model.AbstractCProjectDescriptionStorage; +import org.eclipse.cdt.internal.core.settings.model.ICProjectDescriptionStorageType; +import org.eclipse.core.resources.IProject; +import org.osgi.framework.Version; + +/** + * Concrete implementation of ICProjectDescriptionStorageType + * for instantiating XmlProjectDescriptionStorage2 + */ +public class XmlProjectDescriptionStorage2Factory implements ICProjectDescriptionStorageType { + + public AbstractCProjectDescriptionStorage getProjectDescriptionStorage(CProjectDescriptionStorageTypeProxy type, IProject project, Version version) { + return new XmlProjectDescriptionStorage2(type, project, version); + } + + public boolean createsCProjectXMLFile() { + return true; + } + +} diff --git a/core/org.eclipse.cdt.core/plugin.properties b/core/org.eclipse.cdt.core/plugin.properties index 24babd70fff..44c47922043 100644 --- a/core/org.eclipse.cdt.core/plugin.properties +++ b/core/org.eclipse.cdt.core/plugin.properties @@ -95,4 +95,5 @@ GeneratePDOMApplication.name = GeneratePDOM defaultProvider.name = Default Provider templatesExtensionPoint.name = Templates Extension point templateProcessTypes.name = Process Types Extension point -templateAssociations.name = Template Associations \ No newline at end of file +templateAssociations.name = Template Associations +CProjectDescriptionStorage.name = Project Description Storage Extension point \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index 1c2587d34a8..22242f432f5 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -43,6 +43,11 @@ + + + + + + + + + + + diff --git a/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd b/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd new file mode 100644 index 00000000000..5ea7a2549e0 --- /dev/null +++ b/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd @@ -0,0 +1,140 @@ + + + + + + + + + This extension point allows contributors to provide their own implementation of the CProjectDescriptionStorage backing store. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CProjectDescriptionStorageType is a concrete type of AbstractCProjectDescriptionStorage which is delegated to for persisting ICStorageElement trees + + + + + + + A factory class that implements ICProjectDescriptionStorageType to create AbstractCProjectDescriptionStorages for given IProjects + + + + + + + + + + Id of this particular project description storage type + + + + + + + Version number of this storage type if min_version and max_version are specified, this version must be in the range (min_version, max_version] i.e. min_version < version <= max_version +This String value must be compatible with org.eclipse.osgi.framework.version + + + + + + + The minimum version of project description supported by this description storage type. If this value is not specified then a default Version.emptyVersion is used +This String value must be compatible with org.eclipse.osgi.framework.version + + + + + + + The maximum version of project description supported by this description storage type. If this is not specified then a value equal to version is used. +This String value must be compatible with org.eclipse.osgi.framework.version + + + + + + + Human readable name of this project description type + + + + + + + + + + + + + + + 6.0 + + + + + + + + + + [Enter API information here.] + + + + + + + + + See the example XmlProjectDescriptionStorage & XmlProjectDescriptionStorage2 in this plugin + + + + + diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index fb1539c7bc6..4f1480de68e 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -58,6 +58,7 @@ import org.eclipse.cdt.internal.core.model.WorkingCopy; import org.eclipse.cdt.internal.core.pdom.PDOMManager; import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; @@ -683,13 +684,17 @@ public class CCorePlugin extends Plugin { } public void mapCProjectOwner(IProject project, String id, boolean override) throws CoreException { + try { if (!override) { fNewCProjectDescriptionManager.getDescriptorManager().configure(project, id); } else { fNewCProjectDescriptionManager.getDescriptorManager().convert(project, id); } + } catch (Exception e) { + throw ExceptionFactory.createCoreException(e); + } } - + public ICDescriptorManager getCDescriptorManager() { return fNewCProjectDescriptionManager.getDescriptorManager(); } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java index f12ff90d5db..9576a4f0f9b 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java @@ -8,46 +8,126 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Andrew Ferguson (Symbian) + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.core; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; -import org.w3c.dom.Element; /** * Models meta-data stored with a CDT project + * + * Consumers should ensure that changes made to an ICDescriptor are done + * in the context of an {@link ICDescriptorOperation} + * via {@link ICDescriptorManager#runDescriptorOperation} + * + * @see ICDescriptorOperation + * @see ICDescriptorManager */ public interface ICDescriptor { public ICOwnerInfo getProjectOwner(); public String getPlatform(); - + /** * @return the associated project */ public IProject getProject(); - - public ICExtensionReference[] get(String extensionPoint); - public ICExtensionReference[] get(String extensionPoint, boolean update) throws CoreException; - public ICExtensionReference create(String extensionPoint, String id) throws CoreException; - public void remove(ICExtensionReference extension) throws CoreException; - public void remove(String extensionPoint) throws CoreException; - /** + * Returns an {@link ICExtensionReference}[] corresponding to a particular extensionPoint. + * This array contains all the ICExtensionReferences from all the ICConfigurationDescriptions + * in the project + * @param extensionPointID String extensionPointID + * @return ICExtensionReference[] ICExtensionReference array + * @deprecated + * @use {@link ICConfigurationDescription#get(String)} + */ + @Deprecated + public ICExtensionReference[] get(String extensionPointID); + + /** + * Returns an {@link ICExtensionReference}[] corresponding to a particular extensionPoint. + * This array contains all the ICExtensionReferences from all the ICConfigurationDescriptions + * in the project + * @param extensionPointID String extensionPointID + * @param update updates the COwner + * @return ICExtensionReference[] ICExtensionReference array + * @deprecated + */ + @Deprecated + public ICExtensionReference[] get(String extensionPointID, boolean update) throws CoreException; + + /** + * Create an ICExtensionReference for the given extensionPointId with id = id. + * + * This is not CConfigurationDescription aware and so is added to all configurations in the project. + * You should instead use: + * {@link ICConfigurationDescription#create(String, String)} + * + * @param extensionPointID + * @param id + * @return the create ICExtensionReference + * @throws CoreException + * @deprecated + * @use {@link ICConfigurationDescription#create(String, String)} + */ + @Deprecated + public ICExtensionReference create(String extensionPointID, String id) throws CoreException; + + /** + * Remove a given ICExtensionReference from the project description. + * @param extension + * @throws CoreException + * @deprecated + * @use {@link ICConfigurationDescription#remove(org.eclipse.cdt.core.settings.model.ICConfigExtensionReference)} + */ + @Deprecated + public void remove(ICExtensionReference extension) throws CoreException; + + /** + * Remove ICExtensionReferences with the given extensionPoint from + * this descriptor + * @param extensionPoint + * @throws CoreException + * @deprecated + * @use {@link ICConfigurationDescription#remove(String)} + */ + @Deprecated + public void remove(String extensionPoint) throws CoreException; + + /** + * Return a storage element corresponding to the id in which + * client related metadata may be stored. + * * @param id an identifier that uniquely identifies the client - * @return a non-null {@link Element} to which client specific meta-data may be attached + * @return a non-null {@link ICStorageElement} to which client specific meta-data may be attached + * @throws CoreException + * @since 5.1 + */ + public ICStorageElement getProjectStorageElement(String id) throws CoreException; + + /** + * Remove the storage element with the given ID from the tree + * @param id * @throws CoreException */ - public Element getProjectData(String id) throws CoreException; - + public void removeProjectStorageElement(String id) throws CoreException; + /** - * Saves any changes made to {@link Element} objects obtained from {@link #getProjectData(String)} + * Saves any changes made to {@link ICStorageElement} objects obtained from {@link #getProjectStorageElement(String)} * to a CDT defined project meta-data file. * @throws CoreException */ public void saveProjectData() throws CoreException; - + + /** + * Returns the current settings configuration (which contains this descriptor) -- currently + * equivalent to {@link ICProjectDescription#getDefaultSettingConfiguration()} + * @return the current setting {@link ICConfigurationDescription} + */ ICConfigurationDescription getConfigurationDescription(); } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorManager.java index 4c09ddce5cd..3c171e0e29f 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.core; @@ -20,19 +21,59 @@ public interface ICDescriptorManager { public void configure(IProject project, String id) throws CoreException; public void convert(IProject project, String id) throws CoreException; - + + /** + * Return the ICDescriptor for the project. If project doesn't contain + * an ICDescriptor then one is created. + * Equivalent to: {@link ICDescriptorManager#getDescriptor(IProject, true)} + * + * Users should consider batching changes in an ICDescriptorOperation + * + * @see ICDescriptorManager#getDescriptor(IProject, boolean) + * @param project + * @return ICDescriptor + * @throws CoreException + */ public ICDescriptor getDescriptor(IProject project) throws CoreException; - + + /** + * Return the ICDescriptor for the project. If project doesn't contain + * an ICDescriptor and create == true, then one is created + * + * Users should consider batching changes in an ICDescriptorOperation + * + * @param project + * @param create + * @return ICDescriptor + * @throws CoreException + */ public ICDescriptor getDescriptor(IProject project, boolean create) throws CoreException; + /** + * Atomically runs the descriptor operation on the current project's configuration + * + * The descriptor is automatically 'applied' after the CDescriptorOperation has been run + * @param project + * @param op + * @param monitor + * @throws CoreException + */ public void runDescriptorOperation(IProject project, ICDescriptorOperation op, IProgressMonitor monitor) throws CoreException; - - public void runDescriptorOperation(IProject project, - ICProjectDescription des, - ICDescriptorOperation op, - IProgressMonitor monitor) - throws CoreException; - + + /** + * Runs the ICDescriptorOperation on the provided ICProjectDescription. The changes are reconciled into + * the provided ICProjectDescription. + * + * Currently this project description may be different from the current project description + * @param project + * @param des + * @param op + * @param monitor + * @throws CoreException + */ + public void runDescriptorOperation(IProject project, ICProjectDescription des, ICDescriptorOperation op, + IProgressMonitor monitor) throws CoreException; + public void addDescriptorListener(ICDescriptorListener listener); public void removeDescriptorListener(ICDescriptorListener listener); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorOperation.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorOperation.java index d6e542f6e24..90e50918a35 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorOperation.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptorOperation.java @@ -10,11 +10,22 @@ *******************************************************************************/ package org.eclipse.cdt.core; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; public interface ICDescriptorOperation { + /** + * Call-back method executed atomically on a ICDescriptor in a runnable. + * + * @see ICDescriptorManager#runDescriptorOperation(IProject, ICDescriptorOperation, IProgressMonitor) + * @see ICDescriptorManager#runDescriptorOperation(IProject, ICProjectDescription, ICDescriptorOperation, IProgressMonitor) + * @param descriptor + * @param monitor + * @throws CoreException + */ void execute(ICDescriptor descriptor, IProgressMonitor monitor) throws CoreException; } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtension.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtension.java index 63cedfa610f..1e135408571 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtension.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtension.java @@ -12,6 +12,9 @@ package org.eclipse.cdt.core; import org.eclipse.core.resources.IProject; +/** + * This represents an executable extension in the cmodel hierarchy + */ public interface ICExtension { public IProject getProject(); public ICExtensionReference getExtensionReference(); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtensionReference.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtensionReference.java index 7bf9bb57d07..6bda14a33fc 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtensionReference.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICExtensionReference.java @@ -4,27 +4,39 @@ * 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: * QNX Software Systems - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core; +import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; +/** + * This is reference to {@link ICExtension} elements as stored + * in the Project Description. + * + * This has no notion of the ICConfigurationDescription, + * for that see {@link ICConfigExtensionReference} + * + * @see ICConfigExtensionReference + * @see ICExtension + * @see ICDescriptor + */ public interface ICExtensionReference { /** * Return the extension point of this reference. - * + * * @return String */ public String getExtension(); /** * Return the extension ID of this reference. - * + * * @return String */ public String getID(); @@ -45,19 +57,19 @@ public interface ICExtensionReference { * @return the ICDescriptor */ public ICDescriptor getCDescriptor(); - + /** - * Creates and returns a new instance of the cextension executable + * Creates and returns a new instance of the cextension executable * identified by the <run> attribute of the cextension. *

- * The ICExtension is instantiated using its 0-argument public + * The ICExtension is instantiated using its 0-argument public * constructor. If the class implements the * org.eclipse.core.runtime.IExecutableExtension interface, the method * setInitializationData is called, passing to the object - * the configuration information that was used to create it. + * the configuration information that was used to create it. *

*

- * Unlike other methods on this object, invoking this method may activate + * Unlike other methods on this object, invoking this method may activate * the plug-in. *

* @@ -75,18 +87,18 @@ public interface ICExtensionReference { *

* Each child corresponds to a nested XML element in the configuration * markup. For example, the configuration markup - * + * *

      *  <view>
-     *  &nbsp&nbsp&nbsp&nbsp<verticalHint>top</verticalHint>
-     *  &nbsp&nbsp&nbsp&nbsp<horizontalHint>left</horizontalHint>
+     *      <verticalHint>top</verticalHint>
+     *      <horizontalHint>left</horizontalHint>
      *  </view>
      * 
- * + * * corresponds to a configuration element, named "view", * with two children. *

- * + * * @return the child configuration elements */ public IConfigurationElement[] getExtensionElements() throws CoreException; diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptor.java index 06a5964bfea..c19e5f8d5a4 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptor.java @@ -8,58 +8,143 @@ * Contributors: * Intel Corporation - Initial API and implementation * Anton Leherbauer (Wind River Systems) + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core; -import java.util.ArrayList; -import java.util.Arrays; +import java.text.MessageFormat; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CDescriptorEvent; import org.eclipse.cdt.core.ICDescriptor; +import org.eclipse.cdt.core.ICDescriptorManager; import org.eclipse.cdt.core.ICExtension; import org.eclipse.cdt.core.ICExtensionReference; import org.eclipse.cdt.core.ICOwnerInfo; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.core.settings.model.util.CExtensionUtil; import org.eclipse.cdt.internal.core.settings.model.CConfigurationDescriptionCache; import org.eclipse.cdt.internal.core.settings.model.CConfigurationSpecSettings; import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; -import org.eclipse.cdt.internal.core.settings.model.CStorage; import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; import org.eclipse.cdt.internal.core.settings.model.IInternalCCfgInfo; -import org.eclipse.cdt.internal.core.settings.model.InternalXmlStorageElement; +import org.eclipse.cdt.internal.core.settings.model.SynchronizedStorageElement; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; -import org.w3c.dom.Document; -import org.w3c.dom.Element; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ILock; +import org.eclipse.core.runtime.jobs.Job; -public class CConfigBasedDescriptor implements ICDescriptor { +/** + * Concrete ICDescriptor for a Project. + * + * There is only one of these per project. Settings are serialized into all the + * ICConfigurationDescriptions of the project. Methods which change or access data + * on the descriptor use the Eclipse ILock 'fLock' on the given descriptor instance. + * + * Structural changes made to extension elements are persisted immediately to + * the project description. + * + * Changes made to child storage elements are serialized to the project description + * with saveProjectData(...) and the serializingJob. + * + * Users should consider using {@link ICDescriptorManager#runDescriptorOperation} for threadsafe + * access to the project's configuration. However failing this does provide some basic + * concurrency on {@link #getProjectStorageElement(String)} by wrapping the returned + * ICStorageElement in an {@link SynchronizedStorageElement}. Note that this is best + * effort, so concurrent structural changes to the tree (such as one thread removing + * an element from a tree while another is writing to it) may result in inconsistent data + * stored. + * + */ +final public class CConfigBasedDescriptor implements ICDescriptor { private static final String CEXTENSION_NAME = "cextension"; //$NON-NLS-1$ - + /** The current default setting configuration description + * Equivalent to {@link ICProjectDescription#getDefaultSettingConfiguration()}*/ private ICConfigurationDescription fCfgDes; - private IProject fProject; private COwner fOwner; - private final HashMap> fDesMap = new HashMap>(); - private final HashMap fStorageDataElMap = new HashMap(); - private boolean fApplyOnChange = true; - private boolean fIsDirty; + + /** Map: storageModule ID -> ICStorageElement
+ * CDescriptor's map of so far uncommited storage elements. */ + private final Map fStorageDataElMap = new HashMap(); + private volatile boolean fIsDirty; + /** Current CDescriptor Event which tracks changes between operationStart & operationStop */ private CDescriptorEvent fOpEvent; - private boolean fIsOpStarted; - - final class CConfigBaseDescriptorExtensionReference implements ICExtensionReference{ - private ICConfigExtensionReference fCfgExtRef; + /** Flag indicating whether an operation has started */ + private volatile boolean fIsOpStarted; + + /** This descriptor's lock */ + final ILock fLock = Job.getJobManager().newLock(); + /** + * The Job the actually does the data applying (by getting and setting the current project description) + * saveProjectData never does the saving itself, rather it schedules this job to run. + * During the setCProjectDescriptionOperation the changes in this ICDescriptor are synchronized into the + * project description being persisted. + */ + class SerializingJob extends Job { + public SerializingJob(String name) { + super (name); + setSystem(true); + // This rule must contain that in SetCProjectDescriptionOperation + // (Resource scheduling rules are always obtained before data structure locks to prevent deadlocks.) + setRule(ResourcesPlugin.getWorkspace().getRoot()); + } + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + fLock.acquire(); + // No point scheduling the run if the project is closed... + if (!getProject().isAccessible()) + return Status.CANCEL_STATUS; + serialize(); + } catch (CoreException e) { + CCorePlugin.log(e); + } finally { + fLock.release(); + } + return Status.OK_STATUS; + } + + public void serialize() throws CoreException { + if (!getProject().isAccessible()) + throw ExceptionFactory.createCoreException(MessageFormat.format(CCorePlugin.getResourceString("ProjectDescription.ProjectNotAccessible"), getProject().getName())); //$NON-NLS-1$ + if(fIsDirty) { + ICProjectDescription des = fCfgDes.getProjectDescription(); + if(des.isCdtProjectCreating()) + des.setCdtProjectCreated(); + CProjectDescriptionManager.getInstance().setProjectDescription(getProject(), des); + fIsDirty = false; + } + } + } + SerializingJob serializingJob = new SerializingJob("CConfigBasedDescriptor Serializing Job"); //$NON-NLS-1$ (system) + + /** + * Concrete implementation of ICExtensionReference based on ICConfigExtensionReference elements. + * In the old world ICExtensions had no notion of which configuration they belong to. + * As a result all state that would have be persisted at the ICExtension level is saved to all + * the configurations in the project + * + * This is a lightweight proxy onto ICConfigExtensionReference and doesn't hold any state + * itself (though alters the isDirty state and descriptor event of the containing Descriptor). + */ + final class CConfigBaseDescriptorExtensionReference implements ICExtensionReference { + /** The ICConfigExtensionReference this is based on -- the identifying feature of this ICExtensionReference */ + private final ICConfigExtensionReference fCfgExtRef; CConfigBaseDescriptorExtensionReference(ICConfigExtensionReference cfgRef){ - fCfgExtRef = cfgRef; + fCfgExtRef = cfgRef; } public ICExtension createExtension() throws CoreException { @@ -67,7 +152,7 @@ public class CConfigBasedDescriptor implements ICDescriptor { IConfigurationElement el = CExtensionUtil.getFirstConfigurationElement(fCfgExtRef, CEXTENSION_NAME, false); cExtension = (InternalCExtension)el.createExecutableExtension("run"); //$NON-NLS-1$ cExtension.setExtensionReference(this); - cExtension.setProject(fProject); + cExtension.setProject(getProject()); return (ICExtension)cExtension; } @@ -105,6 +190,18 @@ public class CConfigBasedDescriptor implements ICDescriptor { setOpEvent(new CDescriptorEvent(CConfigBasedDescriptor.this, CDescriptorEvent.CDTPROJECT_CHANGED, 0)); } } + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj instanceof CConfigBaseDescriptorExtensionReference) + return fCfgExtRef.equals(((CConfigBaseDescriptorExtensionReference)obj).fCfgExtRef); + return fCfgExtRef.equals(obj); + } + @Override + public int hashCode() { + return fCfgExtRef.hashCode(); + } } public CConfigBasedDescriptor(ICConfigurationDescription des) throws CoreException{ @@ -114,315 +211,473 @@ public class CConfigBasedDescriptor implements ICDescriptor { public CConfigBasedDescriptor(ICConfigurationDescription des, boolean write) throws CoreException{ updateConfiguration(des, write); } - - public void setApplyOnChange(boolean apply){ - if(fApplyOnChange == apply) - return; - - fApplyOnChange = apply; - } - - public boolean isApplyOnChange(){ - return fApplyOnChange; - } - - public void apply(boolean force) throws CoreException{ - if(force || fIsDirty){ - ICProjectDescription des = fCfgDes.getProjectDescription(); - if(des.isCdtProjectCreating()) - des.setCdtProjectCreated(); - CProjectDescriptionManager.getInstance().setProjectDescription(fProject, des); - fIsDirty = false; - } - } - - private void checkApply() throws CoreException { - if(fApplyOnChange){ - apply(false); - fIsDirty = false; - } else { - fIsDirty = true; - } - } - - public ICExtensionReference create(String extensionPoint, String id) - throws CoreException { - ICConfigExtensionReference ref = fCfgDes.create(extensionPoint, id); - //write is done for all configurations to avoid "data loss" on configuration change - ICProjectDescription des = fCfgDes.getProjectDescription(); - ICConfigurationDescription cfgs[] = des.getConfigurations(); - for (ICConfigurationDescription cfg : cfgs) { - if(cfg != fCfgDes){ - try { - cfg.create(extensionPoint, id); - } catch (CoreException e){ - } - } + /** + * Persist the current project description (to persist changes to the ICExtensions) + * @param force + * @throws CoreException + */ + void apply(boolean force) throws CoreException { + fIsDirty |= force; + if (!fIsDirty) + return; + + // If we're already serializing the project description, schedule a job + // to perform the serialization... + if (CProjectDescriptionManager.getInstance().isCurrentThreadSetProjectDescription()) { + serializingJob.schedule(); + return; + } + + // Deadlock warning: path entry, for example, can do getStorageElement + // in resource delta (while holding the workspace lock). As CModelOperation + // runs the job as a workspace runnable, this leads to potential deadlock. + // + // So before applying, we ensure that we hold the project resource rule + // before getting the 'lock' on the datastructures + +// final IProject project = getProject(); + // Release the lock + final int lockDepth = fLock.getDepth(); + for (int i = 0; i < lockDepth ; ++i) + fLock.release(); + + try { + // This rule must contain that in SetCProjectDescriptionOperation + Job.getJobManager().beginRule(ResourcesPlugin.getWorkspace().getRoot(), new NullProgressMonitor()); + try { + fLock.acquire(); + serializingJob.serialize(); + } finally { + if (lockDepth == 0) // Only release the lock if it wasn't previously held on entrance to this method + fLock.release(); + else // Reacquire the lock to the appropriate depth + for (int i = 0; i < lockDepth - 1; i++) + fLock.acquire(); + } + } finally { + Job.getJobManager().endRule(ResourcesPlugin.getWorkspace().getRoot()); } - - ICExtensionReference r = create(ref); - fIsDirty = true; - checkApply(); - if(isOperationStarted()) - setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); - return r; } - + + private void checkApply() throws CoreException { + apply(false); + } + + /** + * Set the dirty flag + * @param dirty + */ void setDirty(boolean dirty){ fIsDirty = dirty; } - + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#create(java.lang.String, java.lang.String) + */ + public ICExtensionReference create(String extensionPoint, String id) throws CoreException { + try { + fLock.acquire(); + ICConfigExtensionReference ref = fCfgDes.create(extensionPoint, id); + + //write is done for all configurations to avoid "data loss" on configuration change + ICProjectDescription des = fCfgDes.getProjectDescription(); + ICConfigurationDescription cfgs[] = des.getConfigurations(); + for (ICConfigurationDescription cfg : cfgs) { + if(cfg != fCfgDes){ + try { + cfg.create(extensionPoint, id); + } catch (CoreException e){ + CCorePlugin.log(e); + } + } + } + + ICExtensionReference r = new CConfigBaseDescriptorExtensionReference(ref); + fIsDirty = true; + checkApply(); + if(isOperationStarted()) + setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); + return r; + } finally { + fLock.release(); + } + } + + /** + * Equivalent to {@link #updateConfiguration(ICConfigurationDescription, true)} + * @param des the new ICConfigurationDescription + * @throws CoreException + */ public void updateConfiguration(ICConfigurationDescription des) throws CoreException{ updateConfiguration(des, true); } + /** + * Update the currently default (settings) configuration + * @param des + * @param write + * @throws CoreException + */ public void updateConfiguration(ICConfigurationDescription des, boolean write) throws CoreException{ - if(write && des instanceof CConfigurationDescriptionCache) - throw new IllegalArgumentException(); - - fCfgDes = des; - fProject = fCfgDes.getProjectDescription().getProject(); - CConfigurationSpecSettings settings = ((IInternalCCfgInfo)fCfgDes).getSpecSettings(); - fOwner = settings.getCOwner(); -// settings.setDescriptor(this); - fStorageDataElMap.clear(); - } - - private CConfigBaseDescriptorExtensionReference create(ICConfigExtensionReference ref){ - CConfigBaseDescriptorExtensionReference dr = new CConfigBaseDescriptorExtensionReference(ref); - synchronized (fDesMap) { - ArrayList list = fDesMap.get(ref.getExtensionPoint()); - if(list == null){ - list = new ArrayList(1); - fDesMap.put(ref.getExtensionPoint(), list); - } else { - list.ensureCapacity(list.size() + 1); - } - list.add(dr); + try { + fLock.acquire(); + if(write && des instanceof CConfigurationDescriptionCache) + throw new IllegalArgumentException(); + + fCfgDes = des; + CConfigurationSpecSettings settings = ((IInternalCCfgInfo)fCfgDes).getSpecSettings(); + fOwner = settings.getCOwner(); + } finally { + fLock.release(); } - return dr; } + /** + * Attempt to return an ICExtensionReference array based on the ICConfigExtensionReferences + * contained in this project description (which match the extensionPointId). + * + * Fetches all the ICConfigExtensionReferences from the project's configurations. + * + * Previously this cached the current set of ICExtensionReferences, + * but this cache was never used (it was always overwritten by this method). + * + * FIXME re-add caching (the current behaviour mirrors the previous behaviour -- just tidier) + * @return an array of ICExtenionReference + */ public ICExtensionReference[] get(String extensionPoint) { - ICConfigExtensionReference[] rs = fCfgDes.get(extensionPoint); - ArrayList refs = new ArrayList(); - refs.addAll(Arrays.asList(rs)); - - ICConfigurationDescription[] cfgs = - fCfgDes.getProjectDescription().getConfigurations(); - - for (int i=0; i extRefs = new LinkedHashSet(); + + // Add the ICConfigExtensionReferences for the current configuration description + for (ICConfigExtensionReference cfgRes : fCfgDes.get(extensionPoint)) + extRefs.add(new CConfigBaseDescriptorExtensionReference(cfgRes)); + + for (ICConfigurationDescription cfg : fCfgDes.getProjectDescription().getConfigurations()) + if (!cfg.equals(fCfgDes)) + for (ICConfigExtensionReference cfgRes : fCfgDes.get(extensionPoint)) + extRefs.add(new CConfigBaseDescriptorExtensionReference(cfgRes)); + + return extRefs.toArray(new ICExtensionReference[extRefs.size()]); + } finally { + fLock.release(); } - ICConfigExtensionReference cfgRefs[] = - refs.toArray( - new ICConfigExtensionReference[refs.size()]); - - if(cfgRefs.length == 0){ - return new ICExtensionReference[0]; - } - - ICExtensionReference[] extRefs = new ICExtensionReference[cfgRefs.length]; - synchronized (fDesMap) { - ArrayList list = fDesMap.get(extensionPoint); - // if(list == null){ - // list = new ArrayList(cfgRefs.length); - // fDesMap.put(extensionPoint, list); - // } - - // list = (ArrayList)list.clone(); - // - // CConfigBaseDescriptorExtensionReference[] refs = (CConfigBaseDescriptorExtensionReference[])list. - // toArray(new CConfigBaseDescriptorExtensionReference[list.size()]); - int num = cfgRefs.length - 1; - - for(int i = cfgRefs.length - 1; i >= 0; i--){ - ICConfigExtensionReference ref = cfgRefs[i]; - int k= -1; - if (list != null) { - for(k= list.size()-1; k >= 0; k--){ - CConfigBaseDescriptorExtensionReference r = (CConfigBaseDescriptorExtensionReference)list.get(k); - if(r.fCfgExtRef == ref){ - extRefs[num--] = r; - list.remove(k); - break; - } - } - } - if(k < 0){ - extRefs[num--] = new CConfigBaseDescriptorExtensionReference(ref); - } - } - - if(list == null){ - list = new ArrayList(cfgRefs.length); - fDesMap.put(extensionPoint, list); - } else { - list.clear(); - list.ensureCapacity(cfgRefs.length); - } - - list.addAll(Arrays.asList(extRefs)); - list.trimToSize(); - } - return extRefs; } - public ICExtensionReference[] get(String extensionPoint, boolean update) - throws CoreException { - ICExtensionReference[] refs = get(extensionPoint); - if(refs.length == 0 && update){ - boolean prevApplyOnChange = fApplyOnChange; - fApplyOnChange = false; - fOwner.update(fProject, this, extensionPoint); - fApplyOnChange = prevApplyOnChange; - checkApply(); - refs = get(extensionPoint); + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#get(java.lang.String, boolean) + */ + public ICExtensionReference[] get(String extensionPoint, boolean update) throws CoreException { + try { + fLock.acquire(); + ICExtensionReference[] refs = get(extensionPoint); + if(refs.length == 0 && update){ + fOwner.update(getProject(), this, extensionPoint); + checkApply(); + refs = get(extensionPoint); + } + return refs; + } finally { + fLock.release(); } - return get(extensionPoint); } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#getPlatform() + */ public String getPlatform() { - return fOwner.getPlatform(); + try { + fLock.acquire(); + return fOwner.getPlatform(); + } finally { + fLock.release(); + } } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#getProject() + */ public IProject getProject() { - return fProject; + try { + fLock.acquire(); + return fCfgDes.getProjectDescription().getProject(); + } finally { + fLock.release(); + } } - public Element getProjectData(String id) throws CoreException { - // avoid deadlock by using different lock here. - synchronized(fStorageDataElMap /*CProjectDescriptionManager.getInstance()*/){ - Element el = fStorageDataElMap.get(id); - if(el == null || el.getParentNode() == null){ - InternalXmlStorageElement storageEl = (InternalXmlStorageElement)fCfgDes.getStorage(id, false); - if(storageEl == null){ - try { - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = builder.newDocument(); - el = CStorage.createStorageXmlElement(doc, id); - doc.appendChild(el); - } catch (ParserConfigurationException e) { - throw ExceptionFactory.createCoreException(e); - } - } else { - el = CProjectDescriptionManager.getInstance().createXmlElementCopy(storageEl); + /** + * Note that in the current implementation of the xml based project description + * it is not safe to work on the same storage element in more than one thread. + * + * It is likely that doing so will return a concurrent modification exception on the + * returned ICStorageElement. We must allow this as this is how the existing implementation + * behaves. + */ + public ICStorageElement getProjectStorageElement(String id) throws CoreException { + try { + fLock.acquire(); + // Check if the storage element already exists in our local map + SynchronizedStorageElement storageEl = fStorageDataElMap.get(id); + if(storageEl == null){ + ICStorageElement el = fCfgDes.getStorage(id, true); + try { + el = el.createCopy(); + } catch (UnsupportedOperationException e) { + throw ExceptionFactory.createCoreException(e); } - fStorageDataElMap.put(id, el); + storageEl = SynchronizedStorageElement.synchronizedElement(el); + fStorageDataElMap.put(id, storageEl); } - return el; + return storageEl; + } finally { + fLock.release(); + } + } + + public void removeProjectStorageElement(String id) throws CoreException { + try { + fLock.acquire(); + fStorageDataElMap.put(id, null); + } finally { + fLock.release(); } } public ICOwnerInfo getProjectOwner() { - return fOwner; + try { + fLock.acquire(); + return fOwner; + } finally { + fLock.release(); + } } public void remove(ICExtensionReference extension) throws CoreException { - ICConfigExtensionReference ref =((CConfigBaseDescriptorExtensionReference)extension).fCfgExtRef; - fCfgDes.remove(ref); + try { + fLock.acquire(); + ICConfigExtensionReference ref = ((CConfigBaseDescriptorExtensionReference)extension).fCfgExtRef; + fCfgDes.remove(ref); - //write is done for all configurations to avoid "data loss" on configuration change - ICProjectDescription des = fCfgDes.getProjectDescription(); - ICConfigurationDescription cfgs[] = des.getConfigurations(); - for (ICConfigurationDescription cfg : cfgs) { - if(cfg != fCfgDes){ - try { - ICConfigExtensionReference rs[] = cfg.get(ref.getExtensionPoint()); - for (ICConfigExtensionReference element : rs) { - if(ref.getID().equals(element.getID())){ - cfg.remove(element); - break; + // write is done for all configurations to avoid "data loss" on configuration change + for (ICConfigurationDescription cfg : fCfgDes.getProjectDescription().getConfigurations()) { + if(cfg != fCfgDes){ + try { + ICConfigExtensionReference rs[] = cfg.get(ref.getExtensionPoint()); + for (ICConfigExtensionReference element : rs) { + if(ref.getID().equals(element.getID())){ + cfg.remove(element); + break; + } } + } catch (CoreException e) { + CCorePlugin.log(e); } - } catch (CoreException e) { } } + fIsDirty = true; + checkApply(); + if(isOperationStarted()) + setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); + } finally { + fLock.release(); } - fIsDirty = true; - checkApply(); - if(isOperationStarted()) - setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); } public void remove(String extensionPoint) throws CoreException { - fCfgDes.remove(extensionPoint); - - //write is done for all configurations to avoid "data loss" on configuration change - ICProjectDescription des = fCfgDes.getProjectDescription(); - ICConfigurationDescription cfgs[] = des.getConfigurations(); - for (ICConfigurationDescription cfg : cfgs) { - if(cfg != fCfgDes){ - try { - cfg.remove(extensionPoint); - } catch (CoreException e) { + try { + fLock.acquire(); + fCfgDes.remove(extensionPoint); + //write is done for all configurations to avoid "data loss" on configuration change + for (ICConfigurationDescription cfg : fCfgDes.getProjectDescription().getConfigurations()) { + if(cfg != fCfgDes){ + try { + cfg.remove(extensionPoint); + } catch (CoreException e) { + CCorePlugin.log(e); + } } } + fIsDirty = true; + checkApply(); + if(isOperationStarted()) + setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); + } finally { + fLock.release(); } - fIsDirty = true; - checkApply(); - if(isOperationStarted()) - setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.EXTENSION_CHANGED)); } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#saveProjectData() + */ public void saveProjectData() throws CoreException { - if(CProjectDescriptionManager.getInstance().getDescriptorManager().reconsile(this, fCfgDes.getProjectDescription())) - fIsDirty = true; - - checkApply(); - if(isOperationStarted()) - setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, 0)); + try { + fLock.acquire(); + // Reconcile changes into the current project description + if(reconcile(this, fCfgDes.getProjectDescription())) { + // Dirty => Apply + fIsDirty = true; + apply(true); + if(isOperationStarted()) + setOpEvent(new CDescriptorEvent(this, CDescriptorEvent.CDTPROJECT_CHANGED, 0)); + } + } finally { + fLock.release(); + } } - - public Map getStorageDataElMap(){ - @SuppressWarnings("unchecked") - final HashMap clone = (HashMap)fStorageDataElMap.clone(); - return clone; - } - + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptor#getConfigurationDescription() + */ public ICConfigurationDescription getConfigurationDescription() { - return fCfgDes; + try { + fLock.acquire(); + return fCfgDes; + } finally { + fLock.release(); + } } + /* + * Event handling routines + */ + void setOpEvent(CDescriptorEvent event) { - if(!isOperationStarted()) - return; + try { + fLock.acquire(); + if(!isOperationStarted()) + return; - if (event.getType() == CDescriptorEvent.CDTPROJECT_ADDED) { - fOpEvent = event; - } else if (event.getType() == CDescriptorEvent.CDTPROJECT_REMOVED) { - fOpEvent = event; - } else { - if (fOpEvent == null) { + if (event.getType() == CDescriptorEvent.CDTPROJECT_ADDED) { fOpEvent = event; - } else if ( (fOpEvent.getFlags() & event.getFlags()) != event.getFlags()) { - fOpEvent = new CDescriptorEvent(event.getDescriptor(), event.getType(), - fOpEvent.getFlags() | event.getFlags()); + } else if (event.getType() == CDescriptorEvent.CDTPROJECT_REMOVED) { + fOpEvent = event; + } else { + if (fOpEvent == null) { + fOpEvent = event; + } else if ( (fOpEvent.getFlags() & event.getFlags()) != event.getFlags()) { + fOpEvent = new CDescriptorEvent(event.getDescriptor(), event.getType(), + fOpEvent.getFlags() | event.getFlags()); + } } + } finally { + fLock.release(); } } - + boolean isOperationStarted(){ return fIsOpStarted; } - + void operationStart(){ fIsOpStarted = true; } + /** + * Mark the operation as over -- return the CDescriptorEvent + * @return + */ CDescriptorEvent operationStop(){ - fIsOpStarted = false; - CDescriptorEvent e = fOpEvent; - fOpEvent = null; - - return e; + try { + fLock.acquire(); + fIsOpStarted = false; + CDescriptorEvent e = fOpEvent; + fOpEvent = null; + return e; + } finally { + fLock.release(); + } + } + + /* + * + * The reconcile methods below are for copying storage element changes from the current + * CConfigBasedDescriptor to the passed in writable project description + * + */ + /** + * Copies the changes made to the CConfigBasedDescriptor to the ICProjectDescription + * + * The changes are reconciled into all the project's configurations! + * @param descriptor + * @param des + * @return boolean indicating whether changes were made + */ + public static boolean reconcile(CConfigBasedDescriptor descriptor, ICProjectDescription des){ + try { + descriptor.fLock.acquire(); + + Map map = descriptor.fStorageDataElMap; + boolean reconciled = false; + if(!map.isEmpty()){ + for (Map.Entry entry : map.entrySet()) { + String id = entry.getKey(); + SynchronizedStorageElement synchStor = entry.getValue(); + + if (synchStor != null ) { + // Lock the synchronized storage element to prevent further changes + synchronized (synchStor) { + if(reconcile(id, synchStor.getOriginalElement(), des)) + reconciled = true; + } + } else { + if (reconcile(id, null, des)) + reconciled = true; + } + } + } + return reconciled; + } finally { + descriptor.fLock.release(); + } + } + + private static boolean reconcile(String id, ICStorageElement newStorEl, ICProjectDescription des) { + ICConfigurationDescription cfgs[] = des.getConfigurations(); + boolean reconciled = false; + + for(int i = 0; i < cfgs.length; i++){ + try { + if(reconcile(id, newStorEl, cfgs[i])) + reconciled = true; + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + + return reconciled; + } + + private static boolean reconcile(String id, ICStorageElement newStorEl, ICConfigurationDescription cfg) throws CoreException{ + CConfigurationSpecSettings setting = ((IInternalCCfgInfo)cfg).getSpecSettings(); + ICStorageElement storEl = setting.getStorage(id, false); + + boolean modified = false; + + if(storEl != null){ + if(newStorEl == null){ + setting.removeStorage(id); + modified = true; + } else { + if(!newStorEl.equals(storEl)){ + setting.importStorage(id, newStorEl); + modified = true; + } + } + } else { + if(newStorEl != null){ + setting.importStorage(id, newStorEl); + modified = true; + } + } + return modified; } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptorManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptorManager.java index 4ec0d5f1d48..e620cd45b22 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptorManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CConfigBasedDescriptorManager.java @@ -8,15 +8,18 @@ * Contributors: * Intel Corporation - Initial API and implementation * Anton Leherbauer (Wind River Systems) + * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core; -import java.util.Collections; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.SoftReference; +import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CDescriptorEvent; @@ -24,6 +27,7 @@ import org.eclipse.cdt.core.ICDescriptor; import org.eclipse.cdt.core.ICDescriptorListener; import org.eclipse.cdt.core.ICDescriptorManager; import org.eclipse.cdt.core.ICDescriptorOperation; +import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICDescriptionDelta; @@ -35,10 +39,8 @@ import org.eclipse.cdt.internal.core.settings.model.CConfigurationDescriptionCac import org.eclipse.cdt.internal.core.settings.model.CConfigurationSpecSettings; import org.eclipse.cdt.internal.core.settings.model.CProjectDescription; import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; -import org.eclipse.cdt.internal.core.settings.model.CStorage; import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; import org.eclipse.cdt.internal.core.settings.model.IInternalCCfgInfo; -import org.eclipse.cdt.internal.core.settings.model.InternalXmlStorageElement; import org.eclipse.cdt.internal.core.settings.model.PathEntryConfigurationDataProvider; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -49,344 +51,368 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.ILock; -import org.eclipse.core.runtime.jobs.Job; -import org.w3c.dom.Element; -public class CConfigBasedDescriptorManager implements ICDescriptorManager { - private static CConfigBasedDescriptorManager fInstance; +/** + * CConfigBasedDescriptorManager + * + * ICDescriptor settings are set on all the ICConfigurationDescriptions in the + * project's "org.eclipse.core.cdt.settings" storageModule. + * + * The ICDescriptorManager can be used to fetch the current ICDescriptor + * for the project get and set settings in this module in a safe manner. + * + * This thread delegates operations to the particular CConfigBasedDescriptor + * being operated upon. Locking is performed per descriptor. This manager + * provides additional concurrency above any beyond that provided by + * {@link CoreModel#getProjectDescription(IProject)} as each project only + * has one ICDescriptor live at any time. This prevents concurrent modifications + * from overwriting changes made in other threads. + * + * Usage: + * Users should consider making changes to project ICDescriptors using an {@link ICDescriptorOperation} + * with the {@link #runDescriptorOperation} method. + * The ICDescriptor's returned for {@link #getDescriptor} are shared between multiple thread, + * but they are synchronized. This is safe as long as structural changes aren't made to the same + * project storage element from multiple threads. + * + * @see {ICDescriptor} for more + */ +final public class CConfigBasedDescriptorManager implements ICDescriptorManager { + private volatile static CConfigBasedDescriptorManager fInstance; public static final String NULL_OWNER_ID = ""; //$NON-NLS-1$ - private Map fOwnerConfigMap = null; - private ICProjectDescriptionListener fDescriptionListener; - - private static final QualifiedName DESCRIPTOR_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, "CDescriptor"); //$NON-NLS-1$ + private static volatile Map fOwnerConfigMap; + private volatile static ICProjectDescriptionListener fDescriptionListener; - private List fListeners = Collections.synchronizedList(new Vector()); -// private ThreadLocal fApplyingDescriptorMap = new ThreadLocal(); - private ThreadLocal fThreadInfo = new ThreadLocal(); + private Collection fListeners = new CopyOnWriteArraySet(); - private class ThreadInfo { - Map fApplyingDescriptorMap; - Map fOperatingDescriptorMap; - - public Map getApplyingDescriptorMap(boolean create){ - if(fApplyingDescriptorMap == null && create){ - fApplyingDescriptorMap = new HashMap(1); - } - return fApplyingDescriptorMap; - } + /** Map: IProjet -> CConfigBasedDescriptor weak reference
+ * Multiple threads operating concurrently will get the same shared + * ICDescriptor, however we don't keep a reference to this for longer + * than is necessary.*/ + final ConcurrentHashMap> fProjectDescriptorMap = new ConcurrentHashMap>(); - public Map getOperatingDescriptorMap(boolean create){ - if(fOperatingDescriptorMap == null && create){ - fOperatingDescriptorMap = new HashMap(1); - } - return fOperatingDescriptorMap; - } + private CConfigBasedDescriptorManager(){} - } - - private CConfigBasedDescriptorManager(){ - } - public static CConfigBasedDescriptorManager getInstance(){ if(fInstance == null){ - fInstance = getInstanceSynch(); + synchronized (CConfigBasedDescriptor.class) { + if(fInstance == null){ + fInstance = new CConfigBasedDescriptorManager(); + } + } } return fInstance; } - public static synchronized CConfigBasedDescriptorManager getInstanceSynch(){ - if(fInstance == null){ - fInstance = new CConfigBasedDescriptorManager(); - } - return fInstance; - } - - private static final COwnerConfiguration NULLCOwner = new COwnerConfiguration(NULL_OWNER_ID, + private static final COwnerConfiguration NULLCOwner = new COwnerConfiguration(NULL_OWNER_ID, CCorePlugin.getResourceString("CDescriptorManager.internal_owner")); //$NON-NLS-1$ + + /** + * Callback indicating that a project has moved + * @param fromProject + * @param toProject + */ + public void projectMove(IProject fromProject, IProject toProject) { + Reference ref = fProjectDescriptorMap.get(fromProject); + if (ref != null) + fProjectDescriptorMap.putIfAbsent(toProject, ref); + fProjectDescriptorMap.remove(fromProject); + } + + /** + * Callback to remove references the ICDescriptor when the project + * is closed or removed + * @param project + */ + public void projectClosedRemove(IProject project) { + fProjectDescriptorMap.remove(project); + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#configure(org.eclipse.core.resources.IProject, java.lang.String) + */ public void configure(IProject project, String id) throws CoreException { - CConfigBasedDescriptor dr; if (id.equals(NULLCOwner.getOwnerID())) { IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CDescriptorManager.exception.invalid_ownerID"), //$NON-NLS-1$ (Throwable)null); throw new CoreException(status); } - synchronized (CProjectDescriptionManager.getInstance()) { - dr = findDescriptor(project, false); - if (dr != null) { - if (dr.getProjectOwner().getID().equals(NULLCOwner.getOwnerID())) { - // non owned descriptors are simply configure to the new owner no questions ask! - dr = updateDescriptor(project, dr, id); - } else if (!dr.getProjectOwner().getID().equals(id)) { - IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, CCorePlugin.STATUS_CDTPROJECT_EXISTS, - CCorePlugin.getResourceString("CDescriptorManager.exception.alreadyConfigured"), //$NON-NLS-1$ - (Throwable)null); - throw new CoreException(status); + CConfigBasedDescriptor dr = null; + + // Only allow one IProject configure + synchronized (this) { + try { + dr = findDescriptor(project, false); + if (dr != null) { + dr.fLock.acquire(); + if (dr.getProjectOwner().getID().equals(NULLCOwner.getOwnerID())) { + // non owned descriptors are simply configure to the new owner no questions ask! + dr = updateDescriptor(project, dr, id); + } else if (!dr.getProjectOwner().getID().equals(id)) { + IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, CCorePlugin.STATUS_CDTPROJECT_EXISTS, + CCorePlugin.getResourceString("CDescriptorManager.exception.alreadyConfigured"), //$NON-NLS-1$ + (Throwable)null); + throw new CoreException(status); + } else { + return; // already configured with same owner. + } } else { - return; // already configured with same owner. - } - } else { -// try { dr = findDescriptor(project, true); + dr.fLock.acquire(); dr = updateDescriptor(project, dr, id); + } -// } catch (CoreException e) { // if .cdtproject already exists we'll use that -// IStatus status = e.getStatus(); -// if (status.getCode() == CCorePlugin.STATUS_CDTPROJECT_EXISTS) { -// descriptor = new CDescriptor(this, project); -// } else -// throw e; -// } + dr.apply(true); + if(dr.isOperationStarted()) + dr.setOpEvent(new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_ADDED, 0)); + } finally { + if (dr != null) + dr.fLock.release(); } } - - dr.apply(true); - if(dr.isOperationStarted()) - dr.setOpEvent(new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_ADDED, 0)); - } - - private CConfigBasedDescriptor updateDescriptor(IProject project, CConfigBasedDescriptor dr, String ownerId) throws CoreException{ - ICConfigurationDescription cfgDes = dr.getConfigurationDescription(); - ICProjectDescription projDes = cfgDes.getProjectDescription(); - CConfigurationSpecSettings settings = ((IInternalCCfgInfo)cfgDes).getSpecSettings(); - settings.setCOwner(ownerId); - COwner owner = settings.getCOwner(); - setLoaddedDescriptor(projDes, null); - dr = findDescriptor((CProjectDescription)projDes); - dr.setApplyOnChange(false); - owner.configure(project, dr); - dr.setApplyOnChange(true); - - return dr; } + /** + * Update the descriptor to the particular ownerId + * + * FIXME JBB don't twiddle CConfigBasedDescription state here. + * Creates the project description if non found. Locks the CConfigBasedDescriptor while this takes place + * @param project + * @param dr + * @param ownerId + * @return + * @throws CoreException + */ + private CConfigBasedDescriptor updateDescriptor(IProject project, CConfigBasedDescriptor dr, String ownerId) throws CoreException { + try { + dr.fLock.acquire(); + ICConfigurationDescription cfgDes = dr.getConfigurationDescription(); + CConfigurationSpecSettings settings = ((IInternalCCfgInfo)cfgDes).getSpecSettings(); + settings.setCOwner(ownerId); + COwner owner = settings.getCOwner(); + dr = findDescriptor(project, true); + owner.configure(project, dr); + return dr; + } finally { + dr.fLock.release(); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#convert(org.eclipse.core.resources.IProject, java.lang.String) + */ public void convert(IProject project, String id) throws CoreException { CConfigBasedDescriptor dr = findDescriptor(project, false); - if(dr == null){ + if(dr == null) throw ExceptionFactory.createCoreException(CCorePlugin.getResourceString("CConfigBasedDescriptorManager.0")); //$NON-NLS-1$ - } - - - -// boolean applyOnChange = dr.isApplyOnChange(); -// CProjectDescription des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(project); -// if(des == null){ -// throw ExceptionFactory.createCoreException("the project is not a CDT project"); -// } -// ICConfigurationDescription cfgDes = des.getIndexConfiguration(); -// if(cfgDes == null){ -// throw ExceptionFactory.createCoreException("the projecty does not contain valid configurations"); -// } - - synchronized(CProjectDescriptionManager.getInstance()){ + try { + dr.fLock.acquire(); dr = updateDescriptor(project, dr, id); + dr.apply(true); + if(dr.isOperationStarted()) + dr.setOpEvent(new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.OWNER_CHANGED)); + } finally { + dr.fLock.release(); } - - dr.apply(true); - if(dr.isOperationStarted()) - dr.setOpEvent(new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_CHANGED, CDescriptorEvent.OWNER_CHANGED)); } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#getDescriptor(org.eclipse.core.resources.IProject) + */ public ICDescriptor getDescriptor(IProject project) throws CoreException { return getDescriptor(project, true); } - private ILock fInstanceLock = Job.getJobManager().newLock(); - - public ICDescriptor getDescriptor(IProject project, boolean create) - throws CoreException { - if (create) { - synchronized (CProjectDescriptionManager.getInstance()) { - try { - fInstanceLock.acquire(); - return findDescriptor(project, create); - } finally { - fInstanceLock.release(); - } - } - } else // no need to synchronize in this case. - return findDescriptor(project, create); + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#getDescriptor(org.eclipse.core.resources.IProject, boolean) + */ + public ICDescriptor getDescriptor(IProject project, boolean create) throws CoreException { + return findDescriptor(project, create); } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#addDescriptorListener(org.eclipse.cdt.core.ICDescriptorListener) + */ public void addDescriptorListener(ICDescriptorListener listener) { fListeners.add(listener); } + /* + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#removeDescriptorListener(org.eclipse.cdt.core.ICDescriptorListener) + */ public void removeDescriptorListener(ICDescriptorListener listener) { fListeners.remove(listener); } - public void runDescriptorOperation(IProject project, - ICDescriptorOperation op, IProgressMonitor monitor) + /* + * Run the descriptor operation. Lock the descriptor while this takes place... + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#runDescriptorOperation(org.eclipse.core.resources.IProject, org.eclipse.cdt.core.ICDescriptorOperation, org.eclipse.core.runtime.IProgressMonitor) + */ + public void runDescriptorOperation(IProject project, ICDescriptorOperation op, IProgressMonitor monitor) throws CoreException { CConfigBasedDescriptor dr = findDescriptor(project, true); - if (dr == null) { + if (dr == null) throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "Failed to create descriptor", null)); //$NON-NLS-1$ - } - CDescriptorEvent event = null; - synchronized (CProjectDescriptionManager.getInstance()) { - boolean initialApplyOnChange = dr.isApplyOnChange(); - dr.setApplyOnChange(false); + try { + dr.fLock.acquire(); + CDescriptorEvent event = null; try { dr.operationStart(); - op.execute(dr, monitor); + op.execute(dr, monitor); } finally { event = dr.operationStop(); - dr.setApplyOnChange(initialApplyOnChange); } - -// dr.apply(false); + dr.apply(false); + if(event != null) + CConfigBasedDescriptorManager.getInstance().notifyListeners(event); + } finally { + dr.fLock.release(); } - - if(event != null){ - CConfigBasedDescriptorManager.getInstance().notifyListeners(event); - } - - } - - public void runDescriptorOperation(IProject project, - ICProjectDescription des, - ICDescriptorOperation op, - IProgressMonitor monitor) - throws CoreException { - CConfigBasedDescriptor dr = getOperatingDescriptor(project); - if(dr != null){ - throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CConfigBasedDescriptorManager.1"), null)); //$NON-NLS-1$ - } - - if(des.isReadOnly()){ - throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CConfigBasedDescriptorManager.2"), null)); //$NON-NLS-1$ - } - - //create a new descriptor - dr = loadDescriptor((CProjectDescription)des); - - if (dr == null) { - throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CConfigBasedDescriptorManager.3"), null)); //$NON-NLS-1$ - } - - setOperatingDescriptor(project, dr); - -// synchronized (CProjectDescriptionManager.getInstance()) { - dr.setApplyOnChange(false); - try { - op.execute(dr, monitor); - reconsile(dr, des); - } finally { - clearOperatingDescriptor(project); - } -// } - } - - private CConfigBasedDescriptor getLoaddedDescriptor(ICProjectDescription des){ - return (CConfigBasedDescriptor)des.getSessionProperty(DESCRIPTOR_PROPERTY); - } - - private void setLoaddedDescriptor(ICProjectDescription des, CConfigBasedDescriptor dr){ - des.setSessionProperty(DESCRIPTOR_PROPERTY, dr); - } - - private CConfigBasedDescriptor findDescriptor(IProject project, boolean create) throws CoreException{ - CConfigBasedDescriptor dr = getOperatingDescriptor(project); - if(dr != null) - return dr; - - CProjectDescription des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(project, false); - -// CConfigBasedDescriptor dr = null; - if(des == null && create){ - des = createProjDescriptionForDescriptor(project); - } - if(des != null){ - dr = findDescriptor(des); - } - return dr; - } - - private CConfigBasedDescriptor findDescriptor(CProjectDescription des) throws CoreException{ - CConfigBasedDescriptor dr = getApplyingDescriptor(des.getProject()); - if(dr != null) - return dr; - - if(des.isApplying()){ - dr = loadDescriptor(des); - setApplyingDescriptor(des.getProject(), dr); - return dr; - } - - dr = getLoaddedDescriptor(des); - if(dr == null){ - dr = loadDescriptor(des); - if(dr != null && !des.isLoadding()){ - setLoaddedDescriptor(des, dr); - } - } - return dr; - } - - private CProjectDescription createProjDescriptionForDescriptor(final IProject project) throws CoreException{ - final CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); - final CProjectDescription des = (CProjectDescription)mngr.createProjectDescription(project, false, true); - - CConfigurationData data = mngr.createDefaultConfigData(project, PathEntryConfigurationDataProvider.getDataFactory()); - des.createConfiguration(CCorePlugin.DEFAULT_PROVIDER_ID, data); - -// mngr.runWspModification(new IWorkspaceRunnable() { -// -// public void run(IProgressMonitor monitor) throws CoreException { -// if(mngr.getProjectDescription(project, false) == null){ -// mngr.setProjectDescription(project, des); -// } -// } -// -// }, null); - return des; } /* - * creates a new descriptor + * Runs a descriptor operation directly on an ICProjectDescription. + * + * (non-Javadoc) + * @see org.eclipse.cdt.core.ICDescriptorManager#runDescriptorOperation(org.eclipse.core.resources.IProject, org.eclipse.cdt.core.settings.model.ICProjectDescription, org.eclipse.cdt.core.ICDescriptorOperation, org.eclipse.core.runtime.IProgressMonitor) */ - private CConfigBasedDescriptor loadDescriptor(CProjectDescription des) throws CoreException{ - CConfigBasedDescriptor dr = null; + public void runDescriptorOperation(IProject project, ICProjectDescription des, ICDescriptorOperation op, IProgressMonitor monitor) + throws CoreException { + // Ensure that only one of these is running on the project at any one time... + if(des.isReadOnly()) + throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CConfigBasedDescriptorManager.2"), null)); //$NON-NLS-1$ + //create a new descriptor + CConfigBasedDescriptor dr = loadDescriptor((CProjectDescription)des); + if (dr == null) + throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, CCorePlugin.getResourceString("CConfigBasedDescriptorManager.3"), null)); //$NON-NLS-1$ + op.execute(dr, monitor); + // reconcile the changes into the passed in ICProjectDescription + CConfigBasedDescriptor.reconcile(dr, des); + } - if(des != null){ - if(des.isReadOnly()) - des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(des.getProject(), true); - - ICConfigurationDescription cfgDes = des.getDefaultSettingConfiguration(); - if(cfgDes instanceof CConfigurationDescriptionCache){ - des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(des.getProject(), true); - cfgDes = des.getDefaultSettingConfiguration(); - } - - - if(cfgDes != null){ - if(cfgDes.isReadOnly()) - throw ExceptionFactory.createCoreException(CCorePlugin.getResourceString("CConfigBasedDescriptorManager.4")); //$NON-NLS-1$ - - dr = new CConfigBasedDescriptor(cfgDes); - } else if (!des.isCdtProjectCreating()){ - throw ExceptionFactory.createCoreException(CCorePlugin.getResourceString("CConfigBasedDescriptorManager.5")); //$NON-NLS-1$ + /** + * Fetch the ICDescriptor for the project. + * + * If there is no project description and create is specified, then a project + * description is created and a descriptor is returned. + * + * Otherwise a share ICDescriptor is returned for the given project + * + * @param project + * @param create create project description if existing description not found + * @throws CoreException + */ + private CConfigBasedDescriptor findDescriptor(IProject project, boolean create) throws CoreException { + CConfigBasedDescriptor dr = null; + Reference ref = fProjectDescriptorMap.get(project); + if (ref != null) + dr = ref.get(); + if (dr != null) + return dr; + + // Only create one descriptor at a time... + try { + // Use workspace root lock rule here as: + // CoreException in getProjectDescription can lead to a refresh holding a resource lock. + // Meanwhile the lock might be held by a resource notification thread. + + // FIXME JBB we really want to hold a resource lock here... + // However doing so changes the way ProjectDescriptions are created and makes CDescriptor tests fail +// Job.getJobManager().beginRule(ResourcesPlugin.getWorkspace().getRoot(), new NullProgressMonitor()); + +// if (fProjectDescriptorMap.get(project) != null && (dr = fProjectDescriptorMap.get(project).get()) != null) +// return dr; + // None found, create a new one based off of read-only project description + + CProjectDescription des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + if(des == null && create) + des = createProjDescriptionForDescriptor(project); + if(des != null) + dr = loadDescriptor(des); + + // Use the ConcurrentHashMap to ensure that only one descriptor is live at a time (for a given project...) + ref = fProjectDescriptorMap.putIfAbsent(project, new SoftReference(dr)); + if (ref != null) { + // Someone was here before us... + CConfigBasedDescriptor dr1 = ref.get(); + if (dr1 != null) + return dr1; + synchronized (this) { + ref = fProjectDescriptorMap.putIfAbsent(project, new SoftReference(dr)); + if (ref != null) { + // Someone was here before us... + dr1 = ref.get(); + if (dr1 != null) + return dr1; + } + fProjectDescriptorMap.put(project, new SoftReference(dr)); + } } + } finally { +// Job.getJobManager().endRule(ResourcesPlugin.getWorkspace().getRoot()); } - return dr; } - public COwnerConfiguration getOwnerConfiguration(String id) { - if (id.equals(NULLCOwner.getOwnerID())) { + private static CProjectDescription createProjDescriptionForDescriptor(final IProject project) throws CoreException{ + final CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); + final CProjectDescription des = (CProjectDescription)mngr.createProjectDescription(project, false, true); + + CConfigurationData data = mngr.createDefaultConfigData(project, PathEntryConfigurationDataProvider.getDataFactory()); + des.createConfiguration(CCorePlugin.DEFAULT_PROVIDER_ID, data); + return des; + } + + /** + * Creates a new CConfigBasedDescriptor from the passed CProjectDescription + * + * static method does not alter any instance state + * + * @param des + * @return CConfigBasedDescriptor or null + * @throws CoreException + */ + private static CConfigBasedDescriptor loadDescriptor(CProjectDescription des) throws CoreException { + if (des == null) + throw ExceptionFactory.createCoreException("CProjectDescription des is null"); + + if(des.isReadOnly()) + des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(des.getProject(), true); + + ICConfigurationDescription cfgDes = des.getDefaultSettingConfiguration(); + if (cfgDes instanceof CConfigurationDescriptionCache) { + des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(des.getProject(), true); + cfgDes = des.getDefaultSettingConfiguration(); + } + + if (cfgDes != null){ + if(cfgDes.isReadOnly()) + throw ExceptionFactory.createCoreException(CCorePlugin.getResourceString("CConfigBasedDescriptorManager.4")); //$NON-NLS-1$ + return new CConfigBasedDescriptor(cfgDes); + } else if (!des.isCdtProjectCreating()){ + throw ExceptionFactory.createCoreException(CCorePlugin.getResourceString("CConfigBasedDescriptorManager.5")); //$NON-NLS-1$ + } + return null; + } + + public static synchronized COwnerConfiguration getOwnerConfiguration(String id) { + if (id.equals(NULLCOwner.getOwnerID())) return NULLCOwner; - } - if (fOwnerConfigMap == null) { + if (fOwnerConfigMap == null) initializeOwnerConfiguration(); - } COwnerConfiguration config = fOwnerConfigMap.get(id); if (config == null) { // no install owner, lets create place holder config for it. config = new COwnerConfiguration(id, CCorePlugin.getResourceString("CDescriptorManager.owner_not_Installed")); //$NON-NLS-1$ @@ -395,7 +421,7 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { return config; } - private void initializeOwnerConfiguration() { + private static void initializeOwnerConfiguration() { IExtensionPoint extpoint = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID, "CProject"); //$NON-NLS-1$ IExtension extension[] = extpoint.getExtensions(); fOwnerConfigMap = new HashMap(extension.length); @@ -409,89 +435,86 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { } } } - - public void startup(){ - if(fDescriptionListener == null){ - fDescriptionListener = new ICProjectDescriptionListener(){ - public void handleEvent(CProjectDescriptionEvent event) { - doHandleEvent(event); - } - - }; - CProjectDescriptionManager.getInstance().addCProjectDescriptionListener(fDescriptionListener, CProjectDescriptionEvent.APPLIED | CProjectDescriptionEvent.LOADED | CProjectDescriptionEvent.DATA_APPLIED | CProjectDescriptionEvent.ABOUT_TO_APPLY); - } + public void startup(){ + if (fDescriptionListener != null) + return; + fDescriptionListener = new ICProjectDescriptionListener(){ + public void handleEvent(CProjectDescriptionEvent event) { + doHandleEvent(event); + } + }; + CProjectDescriptionManager.getInstance().addCProjectDescriptionListener(fDescriptionListener, + CProjectDescriptionEvent.APPLIED | + CProjectDescriptionEvent.LOADED | + CProjectDescriptionEvent.DATA_APPLIED | + CProjectDescriptionEvent.ABOUT_TO_APPLY); } - + public void shutdown(){ - if(fDescriptionListener != null){ + if(fDescriptionListener != null) CProjectDescriptionManager.getInstance().removeCProjectDescriptionListener(fDescriptionListener); - } + fDescriptionListener = null; } - + + /** + * Hand CProjectDescription events + * @param event + */ private void doHandleEvent(CProjectDescriptionEvent event){ + CConfigBasedDescriptor dr = null; + + // Check for an in memory descriptor matching the current event's project + Reference ref = fProjectDescriptorMap.get(event.getProject()); + if (ref != null) + dr = ref.get(); + // If no delta, return + if (dr == null) + return; + try { - switch(event.getEventType()){ - case CProjectDescriptionEvent.LOADED:{ - CProjectDescription des = (CProjectDescription)event.getNewCProjectDescription(); - CConfigBasedDescriptor dr = getLoaddedDescriptor(des); - if(dr != null){ - //the descriptor was requested while load process - des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(des.getProject(), true); - if(des != null){ - ICConfigurationDescription cfgDescription = des.getDefaultSettingConfiguration(); - if(cfgDescription != null){ - dr.updateConfiguration(cfgDescription); - dr.setDirty(false); - } else { - setLoaddedDescriptor(des, null); - } + dr.fLock.acquire(); + try { + switch(event.getEventType()){ + case CProjectDescriptionEvent.LOADED:{ + // the descriptor was requested while load process + CProjectDescription des = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(event.getProject(), true); + if(des != null){ + ICConfigurationDescription cfgDescription = des.getDefaultSettingConfiguration(); + if(cfgDescription != null){ + dr.updateConfiguration(cfgDescription); + dr.setDirty(false); } } } break; - case CProjectDescriptionEvent.ABOUT_TO_APPLY:{ + case CProjectDescriptionEvent.ABOUT_TO_APPLY:{ + CProjectDescription des = (CProjectDescription)event.getNewCProjectDescription(); + if(des != null + && dr.getConfigurationDescription().getProjectDescription() != des){ + CConfigBasedDescriptor.reconcile(dr, des); + } + } + break; + case CProjectDescriptionEvent.DATA_APPLIED:{ CProjectDescription des = (CProjectDescription)event.getNewCProjectDescription(); if(des != null){ - CConfigBasedDescriptor dr = getLoaddedDescriptor(des); - if(dr != null - && dr.getConfigurationDescription().getProjectDescription() != des){ - reconsile(dr, des); - } + CConfigBasedDescriptor.reconcile(dr, des); } } break; - case CProjectDescriptionEvent.DATA_APPLIED:{ - CProjectDescription des = (CProjectDescription)event.getNewCProjectDescription(); - if(des != null){ - CConfigBasedDescriptor dr = clearApplyingDescriptor(event.getProject()); - if(dr != null){ - reconsile(dr, des); - } - } - } - break; - case CProjectDescriptionEvent.APPLIED: - CProjectDescription newDes = (CProjectDescription)event.getNewCProjectDescription(); - CProjectDescription oldDes = (CProjectDescription)event.getOldCProjectDescription(); - CDescriptorEvent desEvent = null; - CConfigBasedDescriptor dr = null; - ICConfigurationDescription updatedCfg = null; - if(oldDes == null){ - dr = findDescriptor(newDes); - updatedCfg = newDes.getDefaultSettingConfiguration(); - if(dr != null){ + case CProjectDescriptionEvent.APPLIED: + CProjectDescription newDes = (CProjectDescription)event.getNewCProjectDescription(); + CProjectDescription oldDes = (CProjectDescription)event.getOldCProjectDescription(); + CDescriptorEvent desEvent = null; + ICConfigurationDescription updatedCfg = null; + if(oldDes == null){ + updatedCfg = newDes.getDefaultSettingConfiguration(); desEvent = new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_ADDED, 0); - } - } else if(newDes == null) { - dr = findDescriptor(oldDes); - if(dr != null){ + } else if(newDes == null) { desEvent = new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_REMOVED, 0); - } - } else { - dr = findDescriptor(newDes); - updatedCfg = newDes.getDefaultSettingConfiguration(); - if(dr != null){ + } else { + updatedCfg = newDes.getDefaultSettingConfiguration(); ICConfigurationDescription newCfg = newDes.getDefaultSettingConfiguration(); ICConfigurationDescription oldCfg = oldDes.getDefaultSettingConfiguration(); int flags = 0; @@ -505,29 +528,30 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { flags = CProjectDescriptionManager.getInstance().calculateDescriptorFlags(newCfg, oldCfg); } } - + int drEventFlags = descriptionFlagsToDescriptorFlags(flags); -// if(drEventFlags != 0){ + // if(drEventFlags != 0){ desEvent = new CDescriptorEvent(dr, CDescriptorEvent.CDTPROJECT_CHANGED, drEventFlags); -// } + // } + } + if(updatedCfg != null){ + CProjectDescription writableDes = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(event.getProject(), true); + ICConfigurationDescription indexCfg = writableDes.getDefaultSettingConfiguration(); + dr.updateConfiguration(indexCfg); + dr.setDirty(false); } - } - - if(updatedCfg != null && dr != null){ - CProjectDescription writableDes = (CProjectDescription)CProjectDescriptionManager.getInstance().getProjectDescription(event.getProject(), true); - ICConfigurationDescription indexCfg = writableDes.getDefaultSettingConfiguration(); - dr.updateConfiguration(indexCfg); - dr.setDirty(false); - } - if(desEvent != null){ notifyListeners(desEvent); + break; } - break; - } - } catch (CoreException e){ + + } catch (CoreException e){ + CCorePlugin.log(e); + } + } finally { + dr.fLock.release(); } } - + private int descriptionFlagsToDescriptorFlags(int flags){ int result = 0; if((flags & ICDescriptionDelta.EXT_REF) != 0){ @@ -538,6 +562,7 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { } return result; } + private ICDescriptionDelta findCfgDelta(ICDescriptionDelta delta, String id){ if(delta == null) return null; @@ -549,14 +574,9 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { } return null; } - + protected void notifyListeners(final CDescriptorEvent event) { - final ICDescriptorListener[] listeners; - synchronized (fListeners) { - listeners = fListeners.toArray(new ICDescriptorListener[fListeners.size()]); - } - for (int i = 0; i < listeners.length; i++) { - final int index = i; + for (final ICDescriptorListener listener : fListeners) { SafeRunner.run(new ISafeRunnable() { public void handleException(Throwable exception) { @@ -566,148 +586,10 @@ public class CConfigBasedDescriptorManager implements ICDescriptorManager { } public void run() throws Exception { - listeners[index].descriptorChanged(event); + listener.descriptorChanged(event); } }); } } - - public boolean reconsile(CConfigBasedDescriptor descriptor, ICProjectDescription des){ - Map map = descriptor.getStorageDataElMap(); - boolean reconsiled = false; - if(map.size() != 0){ - for(Iterator> iter = map.entrySet().iterator(); iter.hasNext();){ - Map.Entry entry = iter.next(); - String id = entry.getKey(); - Element el = entry.getValue(); - if(reconsile(id, el.getParentNode() != null ? el : null, des)) - reconsiled = true; - } - } - return reconsiled; - } - - private boolean reconsile(String id, Element el, ICProjectDescription des){ - ICConfigurationDescription cfgs[] = des.getConfigurations(); - boolean reconsiled = false; - - for(int i = 0; i < cfgs.length; i++){ - try { - if(reconsile(id, el, cfgs[i])) - reconsiled = true; - } catch (CoreException e) { - CCorePlugin.log(e); - } - } - - return reconsiled; - } - - private boolean reconsile(String id, Element el, ICConfigurationDescription cfg) throws CoreException{ - CConfigurationSpecSettings setting = ((IInternalCCfgInfo)cfg).getSpecSettings(); - InternalXmlStorageElement storEl = (InternalXmlStorageElement)setting.getStorage(id, false); - InternalXmlStorageElement newStorEl = el != null ? CStorage.createStorageElement(el, false) : null; - - boolean modified = false; - - if(storEl != null){ - if(newStorEl == null){ - setting.removeStorage(id); - modified = true; - } else { - if(!newStorEl.matches(storEl)){ - setting.importStorage(id, newStorEl); - modified = true; - } - } - } else { - if(newStorEl != null){ - setting.importStorage(id, newStorEl); - modified = true; - } - } - return modified; - } - - private CConfigBasedDescriptor getApplyingDescriptor(IProject project){ - Map map = getApplyingDescriptorMap(false); - if(map != null){ - return map.get(project); - } - return null; - } - - private void setApplyingDescriptor(IProject project, CConfigBasedDescriptor dr){ - if(dr == null) - clearApplyingDescriptor(project); - else { - Map map = getApplyingDescriptorMap(true); - map.put(project, dr); - } - } - - private CConfigBasedDescriptor clearApplyingDescriptor(IProject project){ - Map map = getApplyingDescriptorMap(false); - if(map != null){ - return map.remove(project); - } - return null; - } - - private Map getApplyingDescriptorMap(boolean create){ - ThreadInfo info = getThreadInfo(create); - if(info == null) - return null; - - return info.getApplyingDescriptorMap(create); -// Map map = (Map)fApplyingDescriptorMap.get(); -// if(map == null && create){ -// map = new HashMap(1); -// fApplyingDescriptorMap.set(map); -// } -// return map; - } - - private CConfigBasedDescriptor getOperatingDescriptor(IProject project){ - Map map = getOperatingDescriptorMap(false); - if(map != null){ - return map.get(project); - } - return null; - } - - private void setOperatingDescriptor(IProject project, CConfigBasedDescriptor dr){ - if(dr == null) - clearOperatingDescriptor(project); - else { - Map map = getOperatingDescriptorMap(true); - map.put(project, dr); - } - } - - private CConfigBasedDescriptor clearOperatingDescriptor(IProject project){ - Map map = getOperatingDescriptorMap(false); - if(map != null){ - return map.remove(project); - } - return null; - } - - private Map getOperatingDescriptorMap(boolean create){ - ThreadInfo info = getThreadInfo(create); - if(info == null) - return null; - - return info.getOperatingDescriptorMap(create); - } - - private ThreadInfo getThreadInfo(boolean create){ - ThreadInfo info = fThreadInfo.get(); - if(info == null && create){ - info = new ThreadInfo(); - fThreadInfo.set(info); - } - return info; - } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties index b1f59edba9f..50858ce1659 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePluginResources.properties @@ -79,6 +79,7 @@ pdom.indexer.name=C/C++ Indexer pdom.indexer.task=Indexing PDOMIndexerJob.updateMonitorJob=Update Monitor PDOMManager.unsupportedVersion=The team-shared index cannot be imported, its format is no longer supported. +ProjectDescription.ProjectNotAccessible=Project: {0} is closed or inaccessible\! CCoreInternals.savePreferencesJob=Save preferences CConfigBasedDescriptorManager.0=the project is not a CDT project CConfigBasedDescriptorManager.1=description based descriptor operation can not be nested diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/cdtvariables/UserDefinedVariableSupplier.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/cdtvariables/UserDefinedVariableSupplier.java index 89f62bcbb70..eb5843358d0 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/cdtvariables/UserDefinedVariableSupplier.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/cdtvariables/UserDefinedVariableSupplier.java @@ -36,10 +36,10 @@ import org.eclipse.cdt.core.cdtvariables.CdtVariableException; import org.eclipse.cdt.core.cdtvariables.ICdtVariable; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.util.CDataUtil; -import org.eclipse.cdt.core.settings.model.util.XmlStorageElement; import org.eclipse.cdt.internal.core.settings.model.CConfigurationSpecSettings; import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; import org.eclipse.cdt.internal.core.settings.model.IInternalCCfgInfo; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorageElement; import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.runtime.CoreException; diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/envvar/StorableEnvironmentLoader.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/envvar/StorableEnvironmentLoader.java index eb1f59f0006..c33c4da63d1 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/envvar/StorableEnvironmentLoader.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/envvar/StorableEnvironmentLoader.java @@ -28,7 +28,7 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.settings.model.util.XmlStorageElement; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorageElement; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/doctools/ProjectMap.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/doctools/ProjectMap.java index 6ae40f47ba0..2ecdd802e9a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/doctools/ProjectMap.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/doctools/ProjectMap.java @@ -27,6 +27,8 @@ import org.w3c.dom.NodeList; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ICDescriptor; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.text.doctools.IDocCommentOwner; @@ -117,23 +119,14 @@ class ProjectMap { private static Map load(IProject project) throws CoreException { Map result= new HashMap(); ICDescriptor pd= CCorePlugin.getDefault().getCProjectDescription(project, true); - Element e= pd.getProjectData(ATTRVAL_STORAGEID); - if(e.hasChildNodes()) { - NodeList commentOwners= e.getElementsByTagName(ELEMENT_DOC_COMMENT_OWNER); - for(int i=0; i i= fMap.values().iterator(); i.hasNext();) { String cid= i.next(); - Element commentNode= data.getOwnerDocument().createElement(ELEMENT_DOC_COMMENT_OWNER); + ICStorageElement commentNode = data.createChild(ELEMENT_DOC_COMMENT_OWNER); commentNode.setAttribute(ATTRKEY_DCO_ID, cid); for(Iterator j= fMap.keySet().iterator(); j.hasNext(); ) { IPath path= j.next(); String ccid= fMap.get(path); if(cid.equals(ccid)) { - Element pathNode= data.getOwnerDocument().createElement(ELEMENT_PATH); + ICStorageElement pathNode = commentNode.createChild(ELEMENT_PATH); pathNode.setAttribute(ATTRKEY_PATH_VALUE, path.toPortableString()); - commentNode.appendChild(pathNode); } } - data.appendChild(commentNode); } pd.saveProjectData(); }