| /********************************************************************** |
| * Copyright (c) 2002,2003 QNX Software Systems Ltd. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v0.5 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v05.html |
| * |
| * Contributors: |
| * QNX Software Systems - Initial API and implementation |
| ***********************************************************************/ |
| package org.eclipse.cdt.internal.core; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStreamWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map.Entry; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.apache.xerces.dom.DocumentImpl; |
| import org.apache.xml.serialize.Method; |
| import org.apache.xml.serialize.OutputFormat; |
| import org.apache.xml.serialize.Serializer; |
| import org.apache.xml.serialize.SerializerFactory; |
| import org.eclipse.cdt.core.CCorePlugin; |
| import org.eclipse.cdt.core.ICDescriptor; |
| import org.eclipse.cdt.core.ICExtension; |
| import org.eclipse.cdt.core.ICExtensionReference; |
| import org.eclipse.cdt.core.ICOwnerInfo; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| 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.IPath; |
| import org.eclipse.core.runtime.IPluginRegistry; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| 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 CDescriptor implements ICDescriptor { |
| private COwner fOwner; |
| private IProject fProject; |
| private HashMap extMap = new HashMap(4); |
| private HashMap extInfoMap = new HashMap(4); |
| private Document dataDoc; |
| |
| static final String DESCRIPTION_FILE_NAME = ".cdtproject"; |
| private static final char[][] NO_CHAR_CHAR = new char[0][]; |
| private static final String PROJECT_DESCRIPTION = "cdtproject"; |
| private static final String PROJECT_EXTENSION = "extension"; |
| private static final String PROJECT_EXTENSION_ATTRIBUTE = "attribute"; |
| private static final String PATH_ENTRY = "cpathentry"; |
| private static final String PROJECT_DATA = "data"; |
| private static final String PROJECT_DATA_ITEM = "item"; |
| private static final String PROJECT_DATA_ID = "id"; |
| |
| private boolean fDirty; |
| private boolean autoSave; |
| |
| protected CDescriptor(IProject project, String id) throws CoreException { |
| fProject = project; |
| IPath projectLocation = project.getDescription().getLocation(); |
| |
| if (projectLocation == null) { |
| projectLocation = getProjectDefaultLocation(project); |
| } |
| IPath descriptionPath = projectLocation.append(DESCRIPTION_FILE_NAME); |
| |
| if (descriptionPath.toFile().exists()) { |
| IStatus status; |
| String ownerID = readCDTProject(descriptionPath); |
| if (ownerID.equals(id)) { |
| fOwner = new COwner(ownerID); |
| status = |
| new Status( |
| IStatus.WARNING, |
| CCorePlugin.PLUGIN_ID, |
| CCorePlugin.STATUS_CDTPROJECT_EXISTS, |
| "CDTProject already exisits", |
| (Throwable) null); |
| } else { |
| status = |
| new Status( |
| IStatus.ERROR, |
| CCorePlugin.PLUGIN_ID, |
| CCorePlugin.STATUS_CDTPROJECT_MISMATCH, |
| "CDTProject already exisits but does not match owner ID of creator", |
| (Throwable) null); |
| } |
| throw new CoreException(status); |
| } |
| fOwner = new COwner(id); |
| } |
| |
| protected CDescriptor(IProject project) throws CoreException { |
| fProject = project; |
| IPath projectLocation = project.getDescription().getLocation(); |
| |
| if (projectLocation == null) { |
| projectLocation = getProjectDefaultLocation(project); |
| } |
| IPath descriptionPath = projectLocation.append(DESCRIPTION_FILE_NAME); |
| |
| if (!descriptionPath.toFile().exists()) { |
| IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "CDTProject file not found", (Throwable) null); |
| throw new CoreException(status); |
| } |
| fOwner = new COwner(readCDTProject(descriptionPath)); |
| } |
| |
| protected CDescriptor(IProject project, COwner owner) throws CoreException { |
| fProject = project; |
| IPath projectLocation = project.getDescription().getLocation(); |
| |
| if (projectLocation == null) { |
| projectLocation = getProjectDefaultLocation(project); |
| } |
| IPath descriptionPath = projectLocation.append(DESCRIPTION_FILE_NAME); |
| |
| if (!descriptionPath.toFile().exists()) { |
| IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "CDTProject file not found", (Throwable) null); |
| throw new CoreException(status); |
| } |
| readCDTProject(descriptionPath); |
| fOwner = owner; |
| setDirty(); |
| } |
| |
| protected COwner getOwner() { |
| return fOwner; |
| } |
| |
| private String readCDTProject(IPath descriptionPath) throws CoreException { |
| FileInputStream file = null; |
| try { |
| file = new FileInputStream(descriptionPath.toFile()); |
| DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| Document document = parser.parse(file); |
| Node node = document.getFirstChild(); |
| if (node.getNodeName().equals(PROJECT_DESCRIPTION)) { |
| String ownerID = node.getAttributes().getNamedItem("id").getNodeValue(); |
| if ( ownerID != null) { |
| readProjectDescription(node); |
| return ownerID; |
| } |
| IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "Missing owner id", null); |
| throw new CoreException(status); |
| } |
| IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "Missing cdtproject element", null); |
| throw new CoreException(status); |
| } catch (Exception e) { |
| IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getLocalizedMessage(), e); |
| throw new CoreException(status); |
| } finally { |
| if (file != null) { |
| try { |
| file.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |
| |
| private IPath getProjectDefaultLocation(IProject project) { |
| return Platform.getLocation().append(project.getFullPath()); |
| } |
| |
| public ICOwnerInfo getProjectOwner() { |
| return fOwner; |
| } |
| |
| public String getPlatform() { |
| return fOwner.getPlatform(); |
| } |
| |
| public IProject getProject() { |
| return fProject; |
| } |
| |
| public ICExtensionReference[] get(String extensionID) { |
| CExtensionReference[] refs = (CExtensionReference[]) extMap.get(extensionID); |
| if (refs == null) |
| return new ICExtensionReference[0]; |
| return refs; |
| } |
| |
| public ICExtensionReference[] get(String extensionID, boolean update) { |
| ICExtensionReference[] ext = get(extensionID); |
| if (ext.length == 0 && update) { |
| try { |
| fOwner.update(fProject, this, extensionID); |
| saveInfo(); |
| ext = get(extensionID); |
| } catch (CoreException e) { |
| } |
| } |
| return ext; |
| } |
| |
| public ICExtensionReference create(String extensionPoint, String extensionID) throws CoreException { |
| CExtensionReference extensions[] = (CExtensionReference[]) extMap.get(extensionPoint); |
| if (extensions == null) { |
| extensions = new CExtensionReference[1]; |
| extMap.put(extensionPoint, extensions); |
| } else { |
| CExtensionReference[] newExtensions = new CExtensionReference[extensions.length + 1]; |
| System.arraycopy(extensions, 0, newExtensions, 0, extensions.length); |
| extensions = newExtensions; |
| extMap.put(extensionPoint, extensions); |
| } |
| extensions[extensions.length - 1] = new CExtensionReference(this, extensionPoint, extensionID); |
| setDirty(); |
| return extensions[extensions.length - 1]; |
| } |
| |
| public void remove(ICExtensionReference ext) throws CoreException { |
| CExtensionReference extensions[] = (CExtensionReference[]) extMap.get(ext.getExtension()); |
| for (int i = 0; i < extensions.length; i++) { |
| if (extensions[i] == ext) { |
| System.arraycopy(extensions, i, extensions, i + 1, extensions.length - 1 - i); |
| CExtensionReference[] newExtensions = new CExtensionReference[extensions.length - 1]; |
| System.arraycopy(extensions, 0, newExtensions, 0, extensions.length); |
| extensions = newExtensions; |
| if (extensions.length == 0) { |
| extMap.put(ext.getExtension(), null); |
| } else { |
| extMap.put(ext.getExtension(), extensions); |
| } |
| setDirty(); |
| } |
| } |
| } |
| |
| public void remove(String extensionPoint) throws CoreException { |
| CExtensionReference extensions[] = (CExtensionReference[]) extMap.get(extensionPoint); |
| if (extensions != null) { |
| extMap.remove(extensionPoint); |
| setDirty(); |
| } |
| } |
| |
| public CExtensionInfo getInfo(CExtensionReference cProjectExtension) { |
| CExtensionInfo info = (CExtensionInfo) extInfoMap.get(cProjectExtension); |
| if (info == null) { |
| info = new CExtensionInfo(); |
| extInfoMap.put(cProjectExtension, info); |
| } |
| return info; |
| } |
| |
| protected void saveInfo() throws CoreException { |
| String xml; |
| if (!isDirty()) { |
| return; |
| } |
| try { |
| xml = getAsXML(); |
| } catch (IOException e) { |
| IStatus s = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getMessage(), e); |
| throw new CoreException(s); |
| } |
| |
| IFile rscFile = getProject().getFile(DESCRIPTION_FILE_NAME); |
| InputStream inputStream = new ByteArrayInputStream(xml.getBytes()); |
| // update the resource content |
| if (rscFile.exists()) { |
| rscFile.setContents(inputStream, IResource.FORCE, null); |
| } else { |
| rscFile.create(inputStream, IResource.FORCE, null); |
| } |
| fDirty = false; |
| } |
| |
| public boolean isAutoSave() { |
| return autoSave; |
| } |
| |
| public void setAutoSave(boolean autoSave) { |
| this.autoSave = autoSave; |
| } |
| |
| protected void setDirty() throws CoreException { |
| fDirty = true; |
| if (isAutoSave()) |
| saveInfo(); |
| } |
| |
| protected boolean isDirty() { |
| return fDirty; |
| } |
| |
| protected String serializeDocument(Document doc) throws IOException { |
| ByteArrayOutputStream s = new ByteArrayOutputStream(); |
| OutputFormat format = new OutputFormat(); |
| format.setIndenting(true); |
| format.setLineSeparator(System.getProperty("line.separator")); //$NON-NLS-1$ |
| Serializer serializer = |
| SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(new OutputStreamWriter(s, "UTF8"), format); |
| serializer.asDOMSerializer().serialize(doc); |
| return s.toString("UTF8"); //$NON-NLS-1$ |
| } |
| |
| private void readProjectDescription(Node node) { |
| Node childNode; |
| ArrayList pathEntries = new ArrayList(); |
| NodeList list = node.getChildNodes(); |
| for (int i = 0; i < list.getLength(); i++) { |
| childNode = list.item(i); |
| if (childNode.getNodeType() == Node.ELEMENT_NODE) { |
| if (childNode.getNodeName().equals(PROJECT_EXTENSION)) { |
| try { |
| decodeProjectExtension((Element) childNode); |
| } catch (CoreException e) { |
| CCorePlugin.log(e); |
| } |
| } else if (childNode.getNodeName().equals(PROJECT_DATA)) { |
| try { |
| decodeProjectData((Element)childNode); |
| } catch (CoreException e) { |
| CCorePlugin.log(e); |
| } |
| } |
| } |
| } |
| } |
| |
| private void decodeProjectExtension(Element element) throws CoreException { |
| ICExtensionReference ext = create(element.getAttribute("point"), element.getAttribute("id")); |
| NodeList extAttrib = element.getChildNodes(); |
| for (int j = 0; j < extAttrib.getLength(); j++) { |
| if (extAttrib.item(j).getNodeName().equals(PROJECT_EXTENSION_ATTRIBUTE)) { |
| NamedNodeMap attrib = extAttrib.item(j).getAttributes(); |
| ext.setExtensionData(attrib.getNamedItem("key").getNodeValue(), attrib.getNamedItem("value").getNodeValue()); |
| } |
| } |
| } |
| |
| |
| protected String getAsXML() throws IOException { |
| Document doc = new DocumentImpl(); |
| Element configRootElement = doc.createElement(PROJECT_DESCRIPTION); |
| doc.appendChild(configRootElement); |
| configRootElement.setAttribute("id", fOwner.getID()); //$NON-NLS-1$ |
| encodeProjectExtensions(doc, configRootElement); |
| encodeProjectData(doc, configRootElement); |
| return serializeDocument(doc); |
| } |
| |
| private void encodeProjectExtensions(Document doc, Element configRootElement) { |
| Element element; |
| Iterator extIterator = extMap.values().iterator(); |
| while (extIterator.hasNext()) { |
| CExtensionReference extension[] = (CExtensionReference[]) extIterator.next(); |
| for (int i = 0; i < extension.length; i++) { |
| configRootElement.appendChild(element = doc.createElement(PROJECT_EXTENSION)); |
| element.setAttribute("point", extension[i].getExtension()); |
| element.setAttribute("id", extension[i].getID()); |
| CExtensionInfo info = (CExtensionInfo) extInfoMap.get(extension[i]); |
| if (info != null) { |
| Iterator attribIterator = info.getAttributes().entrySet().iterator(); |
| while (attribIterator.hasNext()) { |
| Entry entry = (Entry) attribIterator.next(); |
| Element extAttributes = doc.createElement(PROJECT_EXTENSION_ATTRIBUTE); |
| extAttributes.setAttribute("key", (String) entry.getKey()); |
| extAttributes.setAttribute("value", (String) entry.getValue()); |
| element.appendChild(extAttributes); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| protected ICExtension createExtensions(ICExtensionReference ext) throws CoreException { |
| InternalCExtension cExtension = null; |
| IPluginRegistry pluginRegistry = Platform.getPluginRegistry(); |
| IExtensionPoint extensionPoint = pluginRegistry.getExtensionPoint(ext.getExtension()); |
| IExtension extension = extensionPoint.getExtension(ext.getID()); |
| if ( extension == null) { |
| throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, "Extension provider not found.", null)); |
| } |
| IConfigurationElement element[] = extension.getConfigurationElements(); |
| for (int i = 0; i < element.length; i++) { |
| if (element[i].getName().equalsIgnoreCase("cextension")) { |
| cExtension = (InternalCExtension) element[i].createExecutableExtension("run"); |
| cExtension.setExtenionReference(ext); |
| cExtension.setProject(fProject); |
| break; |
| } |
| } |
| return (ICExtension) cExtension; |
| } |
| |
| // The project data allows for the storage of any structured information |
| // into the cdtproject file. |
| private Document getProjectDataDoc() throws CoreException { |
| if (dataDoc == null) { |
| try { |
| dataDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); |
| } catch (ParserConfigurationException e) { |
| throw new CoreException( |
| new Status( |
| IStatus.ERROR, |
| CCorePlugin.PLUGIN_ID, |
| IStatus.ERROR, |
| "getProjectDataDoc", |
| e)); |
| } |
| Element rootElem = dataDoc.createElement(PROJECT_DATA); |
| dataDoc.appendChild(rootElem); |
| } |
| return dataDoc; |
| } |
| |
| private void decodeProjectData(Element data) throws CoreException { |
| Document doc = getProjectDataDoc(); |
| doc.replaceChild(doc.importNode(data, true), doc.getDocumentElement()); |
| } |
| |
| public Element getProjectData(String id) throws CoreException { |
| NodeList nodes = getProjectDataDoc().getDocumentElement().getElementsByTagName(PROJECT_DATA_ITEM); |
| for (int i = 0; i < nodes.getLength(); ++i) { |
| Element element = (Element)nodes.item(i); |
| if (element.getAttribute(PROJECT_DATA_ID).equals(id)) |
| return element; |
| } |
| |
| // Not found, make a new one |
| Element element = dataDoc.createElement(PROJECT_DATA_ITEM); |
| element.setAttribute(PROJECT_DATA_ID, id); |
| dataDoc.getDocumentElement().appendChild(element); |
| return element; |
| } |
| |
| public void saveProjectData() throws CoreException { |
| setDirty(); |
| } |
| |
| private void encodeProjectData(Document doc, Element root) { |
| // Don't create or encode the doc if it isn't there already |
| if (dataDoc != null) |
| root.appendChild(doc.importNode(dataDoc.getDocumentElement(), true)); |
| } |
| } |