/******************************************************************************* * Copyright (c) 2007, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - Initial API and implementation * James Blackburn (Broadcom Corp.) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.language; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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.CCorePreferenceConstants; import org.eclipse.cdt.core.language.ProjectLanguageConfiguration; import org.eclipse.cdt.core.language.WorkspaceLanguageConfiguration; import org.eclipse.cdt.core.settings.model.ICProjectDescription; 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.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.service.prefs.BackingStoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Serializes and deserializes language mappings to and from persistent storage. */ public class LanguageMappingStore { private static final String LANGUAGE_MAPPING_ID = "org.eclipse.cdt.core.language.mapping"; //$NON-NLS-1$ 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$ private static final String ATTRIBUTE_CONFIGURATION = "configuration"; //$NON-NLS-1$ public LanguageMappingStore() { } public ProjectLanguageConfiguration decodeMappings(IProject project) throws CoreException { ProjectLanguageConfiguration config = new ProjectLanguageConfiguration(); ICProjectDescription descriptor = getProjectDescription(project, false); if (descriptor != null) { ICStorageElement rootElement = descriptor.getStorage(LANGUAGE_MAPPING_ID, false); if (rootElement != null) { 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<String, Map<String, String>> decodeProjectContentTypeMappings(ICStorageElement rootElement) { Map<String, Map<String, String>> decodedMappings = new TreeMap<String, Map<String, String>>(); 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<String, String> contentTypeMappings = decodedMappings.get(configuration); if (contentTypeMappings == null) { contentTypeMappings = new TreeMap<String, String>(); decodedMappings.put(configuration, contentTypeMappings); } String contentType = mapping.getAttribute(ATTRIBUTE_CONTENT_TYPE); String language = mapping.getAttribute(ATTRIBUTE_LANGUAGE); contentTypeMappings.put(contentType, language); } return decodedMappings; } protected ICProjectDescription getProjectDescription(IProject project, boolean write) throws CoreException { return CCorePlugin.getDefault().getProjectDescription(project, write); } private Map<String, String> decodeContentTypeMappings(Element rootElement) throws CoreException { return decodeMappings(rootElement, CONTENT_TYPE_MAPPING, ATTRIBUTE_CONTENT_TYPE, ATTRIBUTE_LANGUAGE); } private Map<String, Map<String, String>> decodeFileMappings(ICStorageElement rootElement) throws CoreException { Map<String, Map<String, String>> decodedMappings = new TreeMap<String, Map<String, String>>(); 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<String, String> configurationMappings = decodedMappings.get(path); if (configurationMappings == null) { configurationMappings = new TreeMap<String, String>(); decodedMappings.put(path, configurationMappings); } String configuration = mapping.getAttribute(ATTRIBUTE_CONFIGURATION); String language = mapping.getAttribute(ATTRIBUTE_LANGUAGE); configurationMappings.put(configuration, language); } return decodedMappings; } private Map<String, String> decodeMappings(Element rootElement, String category, String keyName, String valueName) { Map<String, String> decodedMappings = new TreeMap<String, String>(); NodeList mappingElements = rootElement.getElementsByTagName(category); for (int j = 0; j < mappingElements.getLength(); j++) { Element mapping = (Element) mappingElements.item(j); String key = mapping.getAttribute(keyName); String value = mapping.getAttribute(valueName); decodedMappings.put(key, value); } return decodedMappings; } public void storeMappings(IProject project, ProjectLanguageConfiguration config) throws CoreException { ICProjectDescription descriptor = getProjectDescription(project, true); ICStorageElement rootElement = descriptor.getStorage(LANGUAGE_MAPPING_ID, true); // clear all children and settings rootElement.clear(); ICStorageElement projectMappings = rootElement.createChild(PROJECT_MAPPINGS); addProjectContentTypeMappings(config.getContentTypeMappings(), projectMappings); addFileMappings(config.getFileMappings(), projectMappings); CCorePlugin.getDefault().setProjectDescription(project, descriptor); } private void addProjectContentTypeMappings(Map<String, Map<String, String>> contentTypeMappings, ICStorageElement rootElement) { Iterator<Entry<String, Map<String, String>>> entries = contentTypeMappings.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, String>> entry = entries.next(); String configuration = entry.getKey(); Iterator<Entry<String, String>> contentTypeEntries = entry.getValue().entrySet().iterator(); while (contentTypeEntries.hasNext()) { Entry<String, String> configurationEntry = contentTypeEntries.next(); String contentType = configurationEntry.getKey(); String language = configurationEntry.getValue(); ICStorageElement mapping = rootElement.createChild(CONTENT_TYPE_MAPPING); mapping.setAttribute(ATTRIBUTE_CONTENT_TYPE, contentType); mapping.setAttribute(ATTRIBUTE_CONFIGURATION, configuration); mapping.setAttribute(ATTRIBUTE_LANGUAGE, language); } } } public void storeMappings(WorkspaceLanguageConfiguration config) throws CoreException { try { // Encode mappings as XML and serialize as a String. Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element rootElement = doc.createElement(WORKSPACE_MAPPINGS); doc.appendChild(rootElement); addContentTypeMappings(config.getWorkspaceMappings(), rootElement); Transformer serializer = createSerializer(); DOMSource source = new DOMSource(doc); StringWriter buffer = new StringWriter(); StreamResult result = new StreamResult(buffer); serializer.transform(source, result); String encodedMappings = buffer.getBuffer().toString(); IEclipsePreferences node = InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); node.put(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS, encodedMappings); node.flush(); } catch (ParserConfigurationException e) { throw new CoreException(Util.createStatus(e)); } catch (TransformerException e) { throw new CoreException(Util.createStatus(e)); } catch (BackingStoreException e) { throw new CoreException(Util.createStatus(e)); } } public WorkspaceLanguageConfiguration decodeWorkspaceMappings() throws CoreException { IEclipsePreferences node = InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); IEclipsePreferences defaultNode = DefaultScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); String encodedMappings = node.get(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS, null); if (encodedMappings == null) { encodedMappings = defaultNode.get(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS, null); } 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 { Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input); config.setWorkspaceMappings(decodeContentTypeMappings(document.getDocumentElement())); return config; } catch (SAXException e) { throw new CoreException(Util.createStatus(e)); } catch (IOException e) { throw new CoreException(Util.createStatus(e)); } catch (ParserConfigurationException e) { throw new CoreException(Util.createStatus(e)); } } private Transformer createSerializer() throws CoreException { try { return TransformerFactory.newInstance().newTransformer(); } catch (TransformerConfigurationException e) { throw new CoreException(Util.createStatus(e)); } catch (TransformerFactoryConfigurationError e) { throw new CoreException(Util.createStatus(e)); } } private void addMappings(Map<String, String> mappings, Element rootElement, String category, String keyName, String valueName) { Document document = rootElement.getOwnerDocument(); Iterator<Entry<String, String>> entries = mappings.entrySet().iterator(); while (entries.hasNext()) { Entry<String, String> entry = entries.next(); Element mapping = document.createElement(category); mapping.setAttribute(keyName, entry.getKey()); mapping.setAttribute(valueName, entry.getValue()); rootElement.appendChild(mapping); } } private void addContentTypeMappings(Map<String, String> mappings, Element rootElement) { addMappings(mappings, rootElement, CONTENT_TYPE_MAPPING, ATTRIBUTE_CONTENT_TYPE, ATTRIBUTE_LANGUAGE); } private void addFileMappings(Map<String, Map<String, String>> mappings, ICStorageElement rootElement) { for (Map.Entry<String, Map<String, String>> entry : mappings.entrySet()) { ICStorageElement mapping = rootElement.createChild(FILE_MAPPING); String path = entry.getKey(); for (Entry<String, String> 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); } } } }