/******************************************************************************* * Copyright (c) 2005, 2009 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.utils.envvar; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; 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.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.settings.model.ICStorageElement; 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; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * This class implements the common functionality that allows * storing and loading environment variable settings from eclipse properties * * @since 3.0 */ public abstract class StorableEnvironmentLoader { /** * this interface represents the preference node and the preference name * that are used for holding the environment data * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ public interface ISerializeInfo{ /** * {@link IEclipsePreferences} root node in the Preference store * @return the Preferences Node into which environment should be (de) serialized */ Preferences getNode(); /** * Name in the preference store * @return the key in the preference node to use for loading preferences */ String getPrefName(); } /** * Creates the StorableEnvironment clone for a new configuration, say, * based on an existing configuration * * @param context the configuration / workspace context the configuration is to be cloned for * @param base the base environment to copy * @return a StorableEnvironment clone of the configuration's environment * @since 5.2 */ public StorableEnvironment cloneEnvironmentWithContext(Object context, StorableEnvironment base, boolean isReadOnly) { PrefsStorableEnvironment env = new PrefsStorableEnvironment(base, getSerializeInfo(context), isReadOnly); return env; } /** * this method should return the ISerializeInfo representing the information * of where the variable should be stored and loaded * If the given context is not supported this method should return null */ protected abstract ISerializeInfo getSerializeInfo(Object context); /** * Loads the environment from the context's {@link ISerializeInfo}. * * NB the environment in the {@link ISerializeInfo} need not be available * yet. The {@link ISerializeInfo} may be held by the {@link StorableEnvironment} * to pick up any external changes in the environment. * * @param context * @param readOnly * @return StorableEnvironment */ protected StorableEnvironment loadEnvironment(Object context, boolean readOnly) { ISerializeInfo serializeInfo = getSerializeInfo(context); if(serializeInfo == null) return null; return new PrefsStorableEnvironment(serializeInfo, readOnly); } /* * stores the given environment */ protected void storeEnvironment(StorableEnvironment env, Object context, boolean force, boolean flush) throws CoreException{ if(!env.isDirty() && !force) return; ISerializeInfo serializeInfo = getSerializeInfo(context); if(serializeInfo == null) return; if (env instanceof PrefsStorableEnvironment) { ((PrefsStorableEnvironment)env).serialize(); } else { // Backwards compatibility ByteArrayOutputStream stream = storeEnvironmentToStream(env); if(stream == null) return; storeOutputStream(stream,serializeInfo.getNode(), serializeInfo.getPrefName(), flush); env.setDirty(false); } } /** * @param env String representing the encoded environment * @return ICStorageElement tree from the passed in InputStream * or null on failure */ static ICStorageElement environmentStorageFromString(String env) { if (env == null) return null; try{ DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); InputSource inputSource = new InputSource(new ByteArrayInputStream(env.getBytes())); Document document = parser.parse(inputSource); Element el = document.getDocumentElement(); XmlStorageElement rootElement = new XmlStorageElement(el); if(!StorableEnvironment.ENVIRONMENT_ELEMENT_NAME.equals(rootElement.getName())) return null; return rootElement; } catch(ParserConfigurationException e){ CCorePlugin.log(e); } catch(SAXException e) { CCorePlugin.log(e); } catch(IOException e) { CCorePlugin.log(e); } return null; } private ByteArrayOutputStream storeEnvironmentToStream(StorableEnvironment env) throws CoreException{ try{ DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); DocumentBuilder builder= factory.newDocumentBuilder(); Document document= builder.newDocument(); Element el = document.createElement(StorableEnvironment.ENVIRONMENT_ELEMENT_NAME); document.appendChild(el); XmlStorageElement rootElement = new XmlStorageElement(el); env.serialize(rootElement); 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(document); ByteArrayOutputStream stream = new ByteArrayOutputStream(); StreamResult result = new StreamResult(stream); transformer.transform(source, result); return stream; } catch(ParserConfigurationException e){ throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getMessage(), e)); } catch(TransformerConfigurationException e){ throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getMessage(), e)); } catch(TransformerException e){ throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getMessage(), e)); } } /** * Preferences can be encoded as a single long ICStorageElement String * @return String value stored in the node or null if no such value exists. */ static String loadPreferenceNode(ISerializeInfo serializeInfo) { if (serializeInfo == null) return null; return loadPreferenceNode(serializeInfo.getNode(), serializeInfo.getPrefName()); } /** * Returns the value stored in a Preferences node * @param node Preferences node * @param key * @return String value stored in the node or null if no such value exists. */ static String loadPreferenceNode(Preferences node, String key){ if(node == null || key == null) return null; String value = node.get(key, null); if(value == null || value.length() == 0) return null; return value; } private void storeOutputStream(ByteArrayOutputStream stream, Preferences node, String key, boolean flush) throws CoreException{ if(stream == null || node == null || key == null) throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, //TODO:ManagedMakeMessages.getResourceString( "StorableEnvironmentLoader.storeOutputStream.wrong.arguments" //$NON-NLS-1$ //) , null)); byte[] bytes= stream.toByteArray(); String val = null; try { val= new String(bytes, "UTF-8"); //$NON-NLS-1$ } catch (UnsupportedEncodingException e) { val= new String(bytes); } node.put(key,val); if(flush){ try{ node.flush(); } catch(BackingStoreException e){ throw new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, e.getMessage(), e)); } } } }