diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorOldTests.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorOldTests.java new file mode 100644 index 00000000000..90a7afefa20 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/cdescriptor/tests/CDescriptorOldTests.java @@ -0,0 +1,404 @@ +/********************************************************************** + * Copyright (c) 2004, 2008 QNX Software Systems Ltd 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: + * 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 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; +import org.eclipse.cdt.core.CDescriptorEvent; +import org.eclipse.cdt.core.CProjectNature; +import org.eclipse.cdt.core.ICDescriptor; +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.testplugin.CTestPlugin; +import org.eclipse.cdt.internal.core.pdom.PDOMManager; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +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; + +/** + * This class exists because the tests in CDescriptorTests + * are not fixed. + * This class corresponds to the version of + * CDescrptorTests before the changes made in cdt.core 5.1 + * (CVS version 1.12) + */ +public class CDescriptorOldTests extends TestCase { + + static String projectId = CTestPlugin.PLUGIN_ID + ".TestProject"; + static IProject fProject; + static CDescriptorListener listener = new CDescriptorListener(); + static CDescriptorEvent fLastEvent; + + /** + * Constructor for CDescriptorTest. + * + * @param name + */ + public CDescriptorOldTests(String name) { + super(name); + } + + public static Test suite() { + TestSuite suite = new TestSuite(CDescriptorOldTests.class.getName()); + + suite.addTest(new CDescriptorOldTests("testDescriptorCreation")); + suite.addTest(new CDescriptorOldTests("testDescriptorOwner")); + suite.addTest(new CDescriptorOldTests("testExtensionCreation")); + suite.addTest(new CDescriptorOldTests("testExtensionGet")); + suite.addTest(new CDescriptorOldTests("testExtensionData")); + suite.addTest(new CDescriptorOldTests("testExtensionRemove")); + suite.addTest(new CDescriptorOldTests("testProjectDataCreate")); + suite.addTest(new CDescriptorOldTests("testProjectDataDelete")); + suite.addTest(new CDescriptorOldTests("testConcurrentDescriptorCreation")); + suite.addTest(new CDescriptorOldTests("testConcurrentDescriptorCreation2")); + suite.addTest(new CDescriptorOldTests("testDeadlockDuringProjectCreation")); + suite.addTest(new CDescriptorOldTests("testProjectStorageDelete")); + + TestSetup wrapper = new TestSetup(suite) { + + @Override + protected void setUp() throws Exception { + oneTimeSetUp(); + } + + @Override + protected void tearDown() throws Exception { + oneTimeTearDown(); + } + + }; + return wrapper; + } + + private static void addNatureToProject(IProject proj, String natureId, IProgressMonitor monitor) throws CoreException { + IProjectDescription description = proj.getDescription(); + String[] prevNatures = description.getNatureIds(); + String[] newNatures = new String[prevNatures.length + 1]; + System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); + newNatures[prevNatures.length] = natureId; + description.setNatureIds(newNatures); + proj.setDescription(description, monitor); + } + + static public class CDescriptorListener implements ICDescriptorListener { + + public void descriptorChanged(CDescriptorEvent event) { + fLastEvent = event; + } + } + + static void oneTimeSetUp() throws Exception { + CTestPlugin.getWorkspace().run(new IWorkspaceRunnable() { + + public void run(IProgressMonitor monitor) throws CoreException { + IWorkspaceRoot root = CTestPlugin.getWorkspace().getRoot(); + IProject project = root.getProject("testDescriptorProject"); + if (!project.exists()) { + project.create(null); + } else { + project.refreshLocal(IResource.DEPTH_INFINITE, null); + } + if (!project.isOpen()) { + project.open(null); + } + CCorePlugin.getDefault().getCDescriptorManager().addDescriptorListener(listener); + if (!project.hasNature(CProjectNature.C_NATURE_ID)) { + addNatureToProject(project, CProjectNature.C_NATURE_ID, null); + } + fProject = project; + } + }, null); + } + + static void oneTimeTearDown() throws Exception { + fProject.delete(true, true, null); + } + + public void testDescriptorCreation() throws Exception { + CTestPlugin.getWorkspace().run(new IWorkspaceRunnable() { + + public void run(IProgressMonitor monitor) throws CoreException { + CCorePlugin.getDefault().mapCProjectOwner(fProject, projectId, false); + } + }, null); + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_ADDED); + Assert.assertEquals(fLastEvent.getFlags(), 0); + fLastEvent = null; + + Assert.assertEquals(fProject, desc.getProject()); + Assert.assertEquals("*", desc.getPlatform()); + } + + // 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) { + } + } + }; + 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; + } + + // 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 { + int lastLength = 0; + for (int i=0; i<200; ++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); + if (lastLength == 0) + lastLength = countChildElements(desc.getProjectData("testElement")); + final Throwable[] exception= new Throwable[10]; + Thread[] threads= new Thread[10]; + for (int j = 0; j < 10; j++) { + final int indexj = j; + Thread t= new Thread() { + @Override + public void run() { + try { + ICDescriptorOperation operation= new ICDescriptorOperation() { + public void execute(ICDescriptor descriptor, IProgressMonitor monitor) throws CoreException { + assertFalse(descriptor.getConfigurationDescription().isReadOnly()); + Element data = descriptor.getProjectData("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); +// 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(); + } + } + }; + t.start(); + threads[j] = t; + } + for (int j = 0; j < threads.length; j++) { + if (threads[j] != null) { + threads[j].join(); + } + assertNull("Exception occurred: "+exception[j], exception[j]); + } + desc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); + int lengthAfter = countChildElements(desc.getProjectData("testElement")); + lastLength += threads.length; // Update last lengths to what we expect + assertEquals("Iteration count: " + i, lastLength, lengthAfter); + + fLastEvent = null; + } + } + + /** + * 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 + */ + 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(); + 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")); + desc.saveProjectData(); + } catch (CoreException exc) { + } + } + }; + t.start(); + + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + Element data = desc.getProjectData("testElement0"); + data.appendChild(data.getOwnerDocument().createElement("test")); + desc.saveProjectData(); + t.join(); + + fLastEvent = null; + } + } + + 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() { + + } + + public void testExtensionCreation() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICExtensionReference extRef = desc.create("org.eclipse.cdt.testextension", "org.eclipse.cdt.testextensionID"); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); + Assert.assertEquals(fLastEvent.getFlags(), CDescriptorEvent.EXTENSION_CHANGED); + fLastEvent = null; + + Assert.assertEquals("org.eclipse.cdt.testextension", extRef.getExtension()); + Assert.assertEquals("org.eclipse.cdt.testextensionID", extRef.getID()); + } + + public void testExtensionGet() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); + + Assert.assertEquals("org.eclipse.cdt.testextension", extRef[0].getExtension()); + Assert.assertEquals("org.eclipse.cdt.testextensionID", extRef[0].getID()); + } + + public void testExtensionData() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); + extRef[0].setExtensionData("testKey", "testValue"); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); + Assert.assertEquals(fLastEvent.getFlags(), 0); + fLastEvent = null; + + Assert.assertEquals("testValue", extRef[0].getExtensionData("testKey")); + extRef[0].setExtensionData("testKey", null); + Assert.assertEquals(null, extRef[0].getExtensionData("testKey")); + } + + public void testExtensionRemove() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); + desc.remove(extRef[0]); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); + Assert.assertEquals(fLastEvent.getFlags(), CDescriptorEvent.EXTENSION_CHANGED); + fLastEvent = null; + + } + + public void testProjectDataCreate() throws Exception { + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + Element data = desc.getProjectData("testElement"); + data.appendChild(data.getOwnerDocument().createElement("test")); + desc.saveProjectData(); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); + Assert.assertEquals(fLastEvent.getFlags(), 0); + fLastEvent = null; + } + + 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()); + desc.saveProjectData(); + + Assert.assertNotNull(fLastEvent); + Assert.assertEquals(fLastEvent.getDescriptor(), desc); + Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); + Assert.assertEquals(fLastEvent.getFlags(), 0); + fLastEvent = null; + } + + public void testProjectStorageDelete() throws Exception { + // 1st Add an item + ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + Element data = desc.getProjectData("testElement"); + data.appendChild(data.getOwnerDocument().createElement("test")); + desc.saveProjectData(); + + // 2nd remove the storage element containing it + desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + data = desc.getProjectData("testElement"); + data.getParentNode().removeChild(data); + desc.saveProjectData(); + + // 3rd check the item no longer exists + desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); + data = desc.getProjectData("testElement"); + assertTrue(data.getChildNodes().getLength() == 0); + fLastEvent = null; + } + +} diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java index 0cd996bc3b0..367770d9ea4 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java @@ -16,6 +16,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.cdt.core.cdescriptor.tests.CDescriptorTests; +import org.eclipse.cdt.core.cdescriptor.tests.CDescriptorOldTests; import org.eclipse.cdt.core.internal.errorparsers.tests.ErrorParserTests; import org.eclipse.cdt.core.internal.tests.PositionTrackerTests; import org.eclipse.cdt.core.internal.tests.ResourceLookupTests; @@ -56,6 +57,7 @@ public class AutomatedIntegrationSuite extends TestSuite { // Add all success tests suite.addTest(CDescriptorTests.suite()); + suite.addTest(CDescriptorOldTests.suite()); suite.addTest(ErrorParserTests.suite()); suite.addTest(ParserTestSuite.suite()); suite.addTest(AllCoreTests.suite()); 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 c743ee791a0..26e48178015 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 @@ -17,6 +17,8 @@ import org.eclipse.core.runtime.IProgressMonitor; /** * This interface represents the manager of CDT Project descriptions. + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface ICProjectDescriptionManager { /* @@ -42,6 +44,7 @@ public interface ICProjectDescriptionManager { /** * Flag indicating that a new empty ICProjectDescription should be created and returned * (irrespective of whether one already exists) + * @since 5.1 */ public static final int GET_EMPTY_PROJECT_DESCRIPTION = 1 << 4; /** @@ -49,6 +52,7 @@ public interface ICProjectDescriptionManager { * 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 + * @since 5.1 */ public static final int GET_CREATE_DESCRIPTION = 1 << 5; /** @@ -58,6 +62,7 @@ public interface ICProjectDescriptionManager { * * @see #GET_CREATE_DESCRIPTION * @see ICProjectDescription#isCdtProjectCreating() + * @since 5.1 */ public static final int PROJECT_CREATING = 1 << 6; 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 1f69fd38f6a..c958c61f6c5 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 @@ -11,8 +11,6 @@ *******************************************************************************/ 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; @@ -44,6 +42,9 @@ import org.eclipse.core.runtime.IProgressMonitor; * @see ICProjectDescription * @see ICConfigurationDescription * @see ICDescriptor + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface ICSettingsStorage { /** @@ -80,18 +81,21 @@ public interface ICSettingsStorage { * @param el ICStorageElement to be imported * @return ICStorageElement representing the imported storage * @throws UnsupportedOperationException + * @since 5.1 */ 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 + * @since 5.1 */ public boolean isModified(); /** * Return whether this Settings Storage is currently read only * @return whether this storage is readonly + * @since 5.1 */ public boolean isReadOnly(); @@ -100,6 +104,7 @@ public interface ICSettingsStorage { * then modified flag will not be reset * @param readOnly * @param keepModify + * @since 5.1 */ 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 e1a4f6e8946..f208ff1cbbc 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 @@ -25,7 +25,8 @@ import org.eclipse.core.runtime.CoreException; * @see ICSettingsStorage * @see ICProjectDescription * @see ICConfigurationDescription - * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface ICStorageElement { @@ -98,6 +99,7 @@ public interface ICStorageElement { /** * Returns true if this storage element has child ICStorageElements * @return boolean indicating whether this ICStorageElement has children + * @since 5.1 */ boolean hasChildren(); @@ -152,6 +154,7 @@ public interface ICStorageElement { * 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 + * @since 5.1 */ ICStorageElement createCopy() throws UnsupportedOperationException, CoreException; @@ -175,6 +178,7 @@ public interface ICStorageElement { * equal between the two ICStorageElements * @param other * @return boolean indicating equality + * @since 5.1 */ 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 index a8b04388450..54ece8c61bd 100644 --- 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 @@ -23,6 +23,9 @@ import org.w3c.dom.NodeList; * * This allows importing of old style Xml trees into ICStorageElement * based project descriptions + * + * @noextend This class is not intended to be subclassed by clients. + * @since 5.1 */ public class XmlStorageUtil { 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 7988ef6c4b2..cf8b79aec48 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 @@ -138,7 +138,18 @@ public abstract class ResourceChangeHandlerBase implements IResourceChangeListen return false; } } + + /** + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + */ + protected void doHahdleResourceMove(IResourceChangeEvent event, IResourceMoveHandler handler) { + doHandleResourceMove(event, handler); + } + /** + * @since 5.1 + */ protected void doHandleResourceMove(IResourceChangeEvent event, IResourceMoveHandler handler){ switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: 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/core/settings/model/util/XmlStorageElement.java new file mode 100644 index 00000000000..845208296a7 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/XmlStorageElement.java @@ -0,0 +1,449 @@ +/******************************************************************************* + * 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Intel Corporation - Initial API and implementation + * Anton Leherbauer (Wind River Systems) - Bug 253911 + *******************************************************************************/ +package org.eclipse.cdt.core.settings.model.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +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.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * @deprecated + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +@Deprecated +public class XmlStorageElement implements ICStorageElement { + + Element fElement; + private ICStorageElement fParent; + private 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); + } + + 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 = attributeFilters.clone(); + + if(childFilters != null && childFilters.length != 0) + 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; +// } + + private void createChildren(){ + if(fChildrenCreated) + return; + + fChildrenCreated = true; + NodeList list = fElement.getChildNodes(); + int size = list.getLength(); + for(int i = 0; i < size; i++){ + Node node = list.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE + && isChildAlowed(node.getNodeName())){ + createAddChild((Element)node, true, null, null); + } + } + } + + private XmlStorageElement createAddChild(Element element, + boolean alowReferencingParent, + String[] attributeFilters, + String[] childFilters){ + XmlStorageElement child = createChild(element, alowReferencingParent, attributeFilters, childFilters); + fChildList.add(child); + return child; + } + + protected XmlStorageElement createChild(Element element, + boolean alowReferencingParent, + String[] attributeFilters, + String[] childFilters){ + return new XmlStorageElement(element, this, alowReferencingParent, attributeFilters, childFilters); + } + + public ICStorageElement[] getChildren() { + return getChildren(XmlStorageElement.class); + } + + protected ICStorageElement[] getChildren(Class clazz){ + return getChildren(clazz, true); + } + + protected ICStorageElement[] getChildren(boolean load){ + return getChildren(XmlStorageElement.class, 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); + } + + public ICStorageElement getParent() { + return fParentRefAlowed ? fParent : null; + } + + public String getAttribute(String name) { + if(isPropertyAlowed(name) && fElement.hasAttribute(name)) + return fElement.getAttribute(name); + return null; + } + + private boolean isPropertyAlowed(String name){ + if(fAttributeFilters != null){ + return checkString(name, fAttributeFilters); + } + return true; + } + + private boolean isChildAlowed(String name){ + if(fChildFilters != null){ + return checkString(name, fChildFilters); + } + return true; + } + + private boolean checkString(String name, String array[]){ + if(array.length > 0){ + for(int i = 0; i < array.length; i++){ + if(name.equals(array[i])) + return false; + } + } + 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(); + } + } + } + + } + + public void removeAttribute(String name) { + if(isPropertyAlowed(name)) + fElement.removeAttribute(name); + } + + public void setAttribute(String name, String value) { + if(isPropertyAlowed(name)) + fElement.setAttribute(name, value); + } + + public void clear(){ + createChildren(); + + ICStorageElement children[] = (ICStorageElement[])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); + if(node.getNodeType() == Node.TEXT_NODE) + fElement.removeChild(node); + } + } + + public ICStorageElement createChild(String name, + boolean alowReferencingParent, + String[] attributeFilters, + String[] childFilters) { + if(!isChildAlowed(name)) + return null; + Element childElement = fElement.getOwnerDocument().createElement(name); + fElement.appendChild(childElement); + return createAddChild(childElement, alowReferencingParent, attributeFilters, childFilters); + } + + public String getName() { + return fElement.getNodeName(); + } + + public ICStorageElement createChild(String name) { + return createChild(name, true, null, null); + } + + public String getValue() { + Text text = getTextChild(); + if(text != null) + return text.getData(); + return null; + } + + public void setValue(String value) { + Text text = getTextChild(); + if(value != null){ + if(text == null){ + text = fElement.getOwnerDocument().createTextNode(value); + fElement.appendChild(text); + } else { + text.setData(value); + } + } else { + if(text != null){ + fElement.removeChild(text); + } + } + } + + private Text getTextChild(){ + NodeList nodes = fElement.getChildNodes(); + Text text = null; + for(int i = 0; i < nodes.getLength(); i++){ + Node node = nodes.item(i); + if(node.getNodeType() == Node.TEXT_NODE){ + text = (Text)node; + break; + } + } + + return text; + } + + public ICStorageElement importChild(ICStorageElement el) throws UnsupportedOperationException { + return addChild(el, true, null, null); + } + + public ICStorageElement addChild(ICStorageElement el, + boolean alowReferencingParent, + String[] attributeFilters, + String[] childFilters) throws UnsupportedOperationException { + + if(!isChildAlowed(el.getName())) + return null; + + if(el instanceof XmlStorageElement){ + XmlStorageElement xmlStEl = (XmlStorageElement)el; + Element xmlEl = xmlStEl.fElement; + Document thisDoc = fElement.getOwnerDocument(); + Document otherDoc = xmlEl.getOwnerDocument(); + if(!thisDoc.equals(otherDoc)){ + xmlEl = (Element)thisDoc.importNode(xmlEl, true); + } else { + xmlEl = (Element)xmlEl.cloneNode(true); + } + + xmlEl = (Element)fElement.appendChild(xmlEl); + return createAddChild(xmlEl, alowReferencingParent, attributeFilters, childFilters); + } else { + throw new UnsupportedOperationException(); + } + } + + public String[] getAttributeFilters(){ + if(fAttributeFilters != null) + return fAttributeFilters.clone(); + return new String[0]; + } + + public String[] getChildFilters(){ + if(fChildFilters != null) + return fChildFilters.clone(); + return new String[0]; + } + + public boolean isParentRefAlowed(){ + return fParentRefAlowed; + } + + public boolean matches(ICStorageElement el){ + if(!getName().equals(el.getName())) + return false; + + if (!valuesMatch(getValue(), el.getValue())) + return false; + + + String[] attrs = getAttributeNames(); + String[] otherAttrs = el.getAttributeNames(); + if(attrs.length != otherAttrs.length) + return false; + + if(attrs.length != 0){ + Set set = new HashSet(Arrays.asList(attrs)); + set.removeAll(Arrays.asList(otherAttrs)); + if(set.size() != 0) + return false; + + for(int i = 0; i < attrs.length; i++){ + if(!getAttribute(attrs[i]).equals(el.getAttribute(attrs[i]))) + return false; + } + + } + + + XmlStorageElement[] children = (XmlStorageElement[])getChildren(); + ICStorageElement[] otherChildren = el.getChildren(); + + if(children.length != otherChildren.length) + return false; + + if(children.length != 0){ + for(int i = 0; i < children.length; i++){ + if(!children[i].matches(otherChildren[i])) + return false; + } + } + + 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); + 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()]); + } + + /** + * @since 5.1 + */ + public ICStorageElement createCopy() throws UnsupportedOperationException, CoreException { + // todo Auto-generated method stub + return null; + } + + /** + * @since 5.1 + */ + public boolean equals(ICStorageElement other) { + // todo Auto-generated method stub + return false; + } + + /** + * @since 5.1 + */ + public ICStorageElement[] getChildrenByName(String name) { + // todo Auto-generated method stub + return null; + } + + /** + * @since 5.1 + */ + public boolean hasAttribute(String name) { + // todo Auto-generated method stub + return false; + } + + /** + * @since 5.1 + */ + public boolean hasChildren() { + // todo Auto-generated method stub + return false; + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SynchronizedStorageElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SynchronizedStorageElement.java index 045a1e86335..b302db87460 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SynchronizedStorageElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SynchronizedStorageElement.java @@ -65,6 +65,26 @@ public class SynchronizedStorageElement implements ICStorageElement { return new SynchronizedStorageElement(el); } + /** + * Create a synchronized storage element from an existing storage element + * All access to this ICStorageElement tree will be synchronized on the + * returned ICStorageElement object. + * @param el + * @param lock + * @return SynchronizedStorageElement wrapping the original ICStorageElement + */ + public static SynchronizedStorageElement synchronizedElement(ICStorageElement el, Object lock) { + return new SynchronizedStorageElement(el, lock); + } + + /** + * @return the lock used to synchronize this SynchronizedStorage and its children + */ + public Object lock() { + return fLock; + } + + public void clear() { synchronized (fLock) { fEl.clear(); diff --git a/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd b/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd index 5ea7a2549e0..fbf9952a7c8 100644 --- a/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd +++ b/core/org.eclipse.cdt.core/schema/CProjectDescriptionStorage.exsd @@ -13,7 +13,7 @@ - + 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 9576a4f0f9b..a7401e723a2 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 @@ -17,7 +17,7 @@ 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 * @@ -27,6 +27,9 @@ import org.eclipse.core.runtime.CoreException; * * @see ICDescriptorOperation * @see ICDescriptorManager + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface ICDescriptor { public ICOwnerInfo getProjectOwner(); @@ -110,12 +113,26 @@ public interface ICDescriptor { */ public ICStorageElement getProjectStorageElement(String id) throws CoreException; + /** + * This method has been superceded by {@link ICDescriptor#getProjectStorageElement(String)} + * @param id an identifier that uniquely identifies the client + * @return a non-null {@link Element} to which client specific meta-data may be attached + * @throws CoreException + * @deprecated + * @noreference This method is not intended to be referenced by clients. + * @use {@link ICDescriptor#getProjectStorageElement(String)} + */ + @Deprecated + public Element getProjectData(String id) throws CoreException; + /** * Remove the storage element with the given ID from the tree * @param id + * @return the ICStorageElement removed or null if there was none for id * @throws CoreException + * @since 5.1 */ - public void removeProjectStorageElement(String id) throws CoreException; + public ICStorageElement removeProjectStorageElement(String id) throws CoreException; /** * Saves any changes made to {@link ICStorageElement} objects obtained from {@link #getProjectStorageElement(String)} @@ -130,4 +147,5 @@ public interface ICDescriptor { * @return the current setting {@link ICConfigurationDescription} */ ICConfigurationDescription getConfigurationDescription(); + } 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 c19e5f8d5a4..3baa875ec32 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 @@ -12,6 +12,9 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.text.MessageFormat; import java.util.HashMap; import java.util.LinkedHashSet; @@ -36,6 +39,8 @@ import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; 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.SynchronizedStorageElement; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorage; +import org.eclipse.cdt.internal.core.settings.model.xml.XmlStorageElement; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -46,6 +51,8 @@ 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; +import org.w3c.dom.Element; +import org.w3c.dom.Node; /** * Concrete ICDescriptor for a Project. @@ -440,10 +447,88 @@ final public class CConfigBasedDescriptor implements ICDescriptor { } } - public void removeProjectStorageElement(String id) throws CoreException { + /** + * Backwards compatibility method which provides an XML Element. + * Currently relies on the fact that the only implementation if ICStorageElement + * in the core is XmlStorageElement. + */ + public Element getProjectData(String id) throws CoreException { try { fLock.acquire(); - fStorageDataElMap.put(id, null); + // Check if the storage element already exists in our local map + SynchronizedStorageElement storageEl = fStorageDataElMap.get(id); + ICStorageElement el; + if(storageEl == null) { + el = fCfgDes.getStorage(id, true); + try { + el = el.createCopy(); + } catch (UnsupportedOperationException e) { + throw ExceptionFactory.createCoreException(e); + } + + if (!(el instanceof XmlStorageElement)) + throw ExceptionFactory.createCoreException( + "Internal Error: getProjectData(...) currently only supports XmlStorageElement types.", new Exception()); //$NON-NLS-1$ + + // Get the underlying Xml Element + final Element xmlEl = ((XmlStorageElement)el).fElement; + // This proxy synchronizes the storage element's root XML Element + el = new XmlStorageElement((Element)Proxy.newProxyInstance(Element.class.getClassLoader(), new Class[]{Element.class}, new InvocationHandler(){ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Method realMethod = xmlEl.getClass().getMethod(method.getName(), method.getParameterTypes()); + // Now just execute the method + synchronized (xmlEl) { + // If requesting the parent node, then we need another proxy + // so that parent.removeChildNode(...) 'does the right thing' + if (method.getName().equals("getParentNode")) { //$NON-NLS-1$ + final Node parent = (Node)realMethod.invoke(xmlEl, args); + Node parentProxy = (Node)Proxy.newProxyInstance(Node.class.getClassLoader(), new Class[]{Node.class}, new InvocationHandler(){ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Method realMethod = parent.getClass().getMethod(method.getName(), method.getParameterTypes()); + synchronized (xmlEl) { + // Handle the remove child case + if (method.getName().equals("removeChild")) { //$NON-NLS-1$ + if (args[0] instanceof Element && ((Element)args[0]).getAttribute( + XmlStorage.MODULE_ID_ATTRIBUTE).length() > 0) { + ICStorageElement removed = removeProjectStorageElement(((Element)args[0]).getAttribute( + XmlStorage.MODULE_ID_ATTRIBUTE)); + if (removed != null) + return ((XmlStorageElement)((SynchronizedStorageElement)removed).getOriginalElement()).fElement; + return null; + } + } + // else return the realMethod + return realMethod.invoke(parent, args); + } + } + }); + return parentProxy; + } + // Otherwise just execute the method + return realMethod.invoke(xmlEl, args); + } + } + })); + + storageEl = SynchronizedStorageElement.synchronizedElement(el, xmlEl); + fStorageDataElMap.put(id, storageEl); + } else { + el = storageEl.getOriginalElement(); + if (!(el instanceof XmlStorageElement)) + throw ExceptionFactory.createCoreException( + "Internal Error: getProjectData(...) currently only supports XmlStorageElement types.", new Exception()); //$NON-NLS-1$ + } + + return ((XmlStorageElement)el).fElement; + } finally { + fLock.release(); + } + } + + public ICStorageElement removeProjectStorageElement(String id) throws CoreException { + try { + fLock.acquire(); + return fStorageDataElMap.put(id, null); } finally { fLock.release(); } @@ -623,7 +708,7 @@ final public class CConfigBasedDescriptor implements ICDescriptor { if (synchStor != null ) { // Lock the synchronized storage element to prevent further changes - synchronized (synchStor) { + synchronized (synchStor.lock()) { if(reconcile(id, synchStor.getOriginalElement(), des)) reconciled = true; }