blob: 0663c24de055d471ed0bd3b0cca8d078f4396c0b [file] [log] [blame]
/**********************************************************************
* 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));
}
}