/******************************************************************************* * Copyright (c) 2010 Sonatype, Inc. * 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: * Sonatype, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.m2e.core.internal.project; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Map.Entry; import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; import org.osgi.service.prefs.BackingStoreException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.ResolverConfiguration; /** * @TODO anyone can think of a better name? */ public class ResolverConfigurationIO { private static final Logger log = LoggerFactory.getLogger(ResolverConfigurationIO.class); /** * Configuration version project preference key. */ private static final String P_VERSION = "version"; //$NON-NLS-1$ /** * Workspace dependency resolution project preference key. Boolean, <code>true</code> means workspace dependency * resolution is enabled. */ private static final String P_RESOLVE_WORKSPACE_PROJECTS = "resolveWorkspaceProjects"; //$NON-NLS-1$ /** * Active profiles project preference key. Value is comma-separated list of enabled profiles. */ //FIXME Bug 337353 Can't rename the preference key as it would break existing projects private static final String P_SELECTED_PROFILES = "activeProfiles"; //$NON-NLS-1$ /** * Lifecycle mapping id configured for the project explicitly. */ private static final String P_LIFECYCLE_MAPPING_ID = "lifecycleMappingId"; private static final String P_PROPERTIES = "properties"; private static final String PROPERTIES_KV_SEPARATOR = ">"; private static final String PROPERTIES_SEPARATOR = "|"; private static final String ENCODING = "UTF-8"; /** * Current configuration version value. See {@link #P_VERSION} */ private static final String VERSION = "1"; //$NON-NLS-1$ public static boolean saveResolverConfiguration(IProject project, ResolverConfiguration configuration) { IScopeContext projectScope = new ProjectScope(project); IEclipsePreferences projectNode = projectScope.getNode(IMavenConstants.PLUGIN_ID); if(projectNode != null) { projectNode.put(P_VERSION, VERSION); projectNode.putBoolean(P_RESOLVE_WORKSPACE_PROJECTS, configuration.shouldResolveWorkspaceProjects()); projectNode.put(P_SELECTED_PROFILES, configuration.getSelectedProfiles()); if(configuration.getLifecycleMappingId() != null) { projectNode.put(P_LIFECYCLE_MAPPING_ID, configuration.getLifecycleMappingId()); } else { projectNode.remove(P_LIFECYCLE_MAPPING_ID); } if(configuration.getProperties() != null && !configuration.getProperties().isEmpty()) { projectNode.put(P_PROPERTIES, propertiesAsString(configuration.getProperties())); } else { projectNode.remove(P_PROPERTIES); } try { projectNode.flush(); return true; } catch(BackingStoreException ex) { log.error("Failed to save resolver configuration", ex); } } return false; } public static ResolverConfiguration readResolverConfiguration(IProject project) { IScopeContext projectScope = new ProjectScope(project); IEclipsePreferences projectNode = projectScope.getNode(IMavenConstants.PLUGIN_ID); if(projectNode == null) { return new ResolverConfiguration(); } String version = projectNode.get(P_VERSION, null); if(version == null) { // migrate from old config // return LegacyBuildPathManager.getResolverConfiguration(project); return new ResolverConfiguration(); } ResolverConfiguration configuration = new ResolverConfiguration(); configuration.setResolveWorkspaceProjects(projectNode.getBoolean(P_RESOLVE_WORKSPACE_PROJECTS, false)); configuration.setSelectedProfiles(projectNode.get(P_SELECTED_PROFILES, "")); //$NON-NLS-1$ configuration.setLifecycleMappingId(projectNode.get(P_LIFECYCLE_MAPPING_ID, (String) null)); configuration.setProperties(stringAsProperties(projectNode.get(P_PROPERTIES, null))); return configuration; } private static String propertiesAsString(Properties properties) { Stream<Entry<Object, Object>> stream = properties.entrySet().stream(); String propAsString = stream.map(e -> encodeEntry(e)).collect(Collectors.joining(PROPERTIES_SEPARATOR)); return propAsString; } private static Properties stringAsProperties(String properties) { Properties p = new Properties(); if(properties != null) { String[] entries = properties.split("\\" + PROPERTIES_SEPARATOR); Stream.of(entries).forEach(e -> convert(e, p)); } return p; } private static void convert(String e, Properties p) { String[] kv = e.split(PROPERTIES_KV_SEPARATOR); String key = kv[0]; String value = null; if(kv.length == 2) { value = kv[1]; } p.put(urlDecode(key), urlDecode(value)); } private static String encodeEntry(Entry<Object, Object> e) { String key = e.getKey().toString(); String value = e.getValue() == null ? "" : e.getValue().toString(); return urlEncode(key) + PROPERTIES_KV_SEPARATOR + urlEncode(value); } private static String urlEncode(String string) { if(string == null) { return ""; } try { return URLEncoder.encode(string, ENCODING); } catch(UnsupportedEncodingException notGonnaHappen) { } return string; } private static String urlDecode(String string) { if(string == null) { return ""; } try { return URLDecoder.decode(string, ENCODING); } catch(UnsupportedEncodingException notGonnaHappen) { } return string; } }