001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.cli.compiler.maven; 018 019import java.io.BufferedReader; 020import java.io.File; 021import java.io.PrintWriter; 022import java.io.StringReader; 023import java.io.StringWriter; 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.maven.model.ActivationFile; 030import org.apache.maven.model.ActivationOS; 031import org.apache.maven.model.ActivationProperty; 032import org.apache.maven.model.building.ModelProblemCollector; 033import org.apache.maven.model.building.ModelProblemCollectorRequest; 034import org.apache.maven.model.path.DefaultPathTranslator; 035import org.apache.maven.model.profile.DefaultProfileSelector; 036import org.apache.maven.model.profile.ProfileActivationContext; 037import org.apache.maven.model.profile.activation.FileProfileActivator; 038import org.apache.maven.model.profile.activation.JdkVersionProfileActivator; 039import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator; 040import org.apache.maven.model.profile.activation.PropertyProfileActivator; 041import org.apache.maven.settings.Activation; 042import org.apache.maven.settings.Mirror; 043import org.apache.maven.settings.Profile; 044import org.apache.maven.settings.Proxy; 045import org.apache.maven.settings.Server; 046import org.apache.maven.settings.Settings; 047import org.apache.maven.settings.crypto.SettingsDecryptionResult; 048import org.eclipse.aether.repository.Authentication; 049import org.eclipse.aether.repository.AuthenticationSelector; 050import org.eclipse.aether.repository.MirrorSelector; 051import org.eclipse.aether.repository.ProxySelector; 052import org.eclipse.aether.util.repository.AuthenticationBuilder; 053import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector; 054import org.eclipse.aether.util.repository.DefaultAuthenticationSelector; 055import org.eclipse.aether.util.repository.DefaultMirrorSelector; 056import org.eclipse.aether.util.repository.DefaultProxySelector; 057 058/** 059 * An encapsulation of settings read from a user's Maven settings.xml. 060 * 061 * @author Andy Wilkinson 062 * @since 1.3.0 063 * @see MavenSettingsReader 064 */ 065public class MavenSettings { 066 067 private final boolean offline; 068 069 private final MirrorSelector mirrorSelector; 070 071 private final AuthenticationSelector authenticationSelector; 072 073 private final ProxySelector proxySelector; 074 075 private final String localRepository; 076 077 private final List<Profile> activeProfiles; 078 079 /** 080 * Create a new {@link MavenSettings} instance. 081 * @param settings the source settings 082 * @param decryptedSettings the decrypted settings 083 */ 084 public MavenSettings(Settings settings, SettingsDecryptionResult decryptedSettings) { 085 this.offline = settings.isOffline(); 086 this.mirrorSelector = createMirrorSelector(settings); 087 this.authenticationSelector = createAuthenticationSelector(decryptedSettings); 088 this.proxySelector = createProxySelector(decryptedSettings); 089 this.localRepository = settings.getLocalRepository(); 090 this.activeProfiles = determineActiveProfiles(settings); 091 } 092 093 private MirrorSelector createMirrorSelector(Settings settings) { 094 DefaultMirrorSelector selector = new DefaultMirrorSelector(); 095 for (Mirror mirror : settings.getMirrors()) { 096 selector.add(mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, 097 mirror.getMirrorOf(), mirror.getMirrorOfLayouts()); 098 } 099 return selector; 100 } 101 102 private AuthenticationSelector createAuthenticationSelector( 103 SettingsDecryptionResult decryptedSettings) { 104 DefaultAuthenticationSelector selector = new DefaultAuthenticationSelector(); 105 for (Server server : decryptedSettings.getServers()) { 106 AuthenticationBuilder auth = new AuthenticationBuilder(); 107 auth.addUsername(server.getUsername()).addPassword(server.getPassword()); 108 auth.addPrivateKey(server.getPrivateKey(), server.getPassphrase()); 109 selector.add(server.getId(), auth.build()); 110 } 111 return new ConservativeAuthenticationSelector(selector); 112 } 113 114 private ProxySelector createProxySelector( 115 SettingsDecryptionResult decryptedSettings) { 116 DefaultProxySelector selector = new DefaultProxySelector(); 117 for (Proxy proxy : decryptedSettings.getProxies()) { 118 Authentication authentication = new AuthenticationBuilder() 119 .addUsername(proxy.getUsername()).addPassword(proxy.getPassword()) 120 .build(); 121 selector.add( 122 new org.eclipse.aether.repository.Proxy(proxy.getProtocol(), 123 proxy.getHost(), proxy.getPort(), authentication), 124 proxy.getNonProxyHosts()); 125 } 126 return selector; 127 } 128 129 private List<Profile> determineActiveProfiles(Settings settings) { 130 SpringBootCliModelProblemCollector problemCollector = new SpringBootCliModelProblemCollector(); 131 List<org.apache.maven.model.Profile> activeModelProfiles = createProfileSelector() 132 .getActiveProfiles(createModelProfiles(settings.getProfiles()), 133 new SpringBootCliProfileActivationContext( 134 settings.getActiveProfiles()), 135 problemCollector); 136 if (!problemCollector.getProblems().isEmpty()) { 137 throw new IllegalStateException(createFailureMessage(problemCollector)); 138 } 139 List<Profile> activeProfiles = new ArrayList<>(); 140 Map<String, Profile> profiles = settings.getProfilesAsMap(); 141 for (org.apache.maven.model.Profile modelProfile : activeModelProfiles) { 142 activeProfiles.add(profiles.get(modelProfile.getId())); 143 } 144 return activeProfiles; 145 } 146 147 private String createFailureMessage( 148 SpringBootCliModelProblemCollector problemCollector) { 149 StringWriter message = new StringWriter(); 150 PrintWriter printer = new PrintWriter(message); 151 printer.println("Failed to determine active profiles:"); 152 for (ModelProblemCollectorRequest problem : problemCollector.getProblems()) { 153 String location = (problem.getLocation() != null) 154 ? " at " + problem.getLocation() : ""; 155 printer.println(" " + problem.getMessage() + location); 156 if (problem.getException() != null) { 157 printer.println(indentStackTrace(problem.getException(), " ")); 158 } 159 } 160 return message.toString(); 161 } 162 163 private String indentStackTrace(Exception ex, String indent) { 164 return indentLines(printStackTrace(ex), indent); 165 } 166 167 private String printStackTrace(Exception ex) { 168 StringWriter stackTrace = new StringWriter(); 169 PrintWriter printer = new PrintWriter(stackTrace); 170 ex.printStackTrace(printer); 171 return stackTrace.toString(); 172 } 173 174 private String indentLines(String input, String indent) { 175 StringWriter indented = new StringWriter(); 176 PrintWriter writer = new PrintWriter(indented); 177 BufferedReader reader = new BufferedReader(new StringReader(input)); 178 reader.lines().forEach((line) -> writer.println(indent + line)); 179 return indented.toString(); 180 } 181 182 private DefaultProfileSelector createProfileSelector() { 183 DefaultProfileSelector selector = new DefaultProfileSelector(); 184 185 selector.addProfileActivator(new FileProfileActivator() 186 .setPathTranslator(new DefaultPathTranslator())); 187 selector.addProfileActivator(new JdkVersionProfileActivator()); 188 selector.addProfileActivator(new PropertyProfileActivator()); 189 selector.addProfileActivator(new OperatingSystemProfileActivator()); 190 return selector; 191 } 192 193 private List<org.apache.maven.model.Profile> createModelProfiles( 194 List<Profile> profiles) { 195 List<org.apache.maven.model.Profile> modelProfiles = new ArrayList<>(); 196 for (Profile profile : profiles) { 197 org.apache.maven.model.Profile modelProfile = new org.apache.maven.model.Profile(); 198 modelProfile.setId(profile.getId()); 199 if (profile.getActivation() != null) { 200 modelProfile 201 .setActivation(createModelActivation(profile.getActivation())); 202 } 203 modelProfiles.add(modelProfile); 204 } 205 return modelProfiles; 206 } 207 208 private org.apache.maven.model.Activation createModelActivation( 209 Activation activation) { 210 org.apache.maven.model.Activation modelActivation = new org.apache.maven.model.Activation(); 211 modelActivation.setActiveByDefault(activation.isActiveByDefault()); 212 if (activation.getFile() != null) { 213 ActivationFile activationFile = new ActivationFile(); 214 activationFile.setExists(activation.getFile().getExists()); 215 activationFile.setMissing(activation.getFile().getMissing()); 216 modelActivation.setFile(activationFile); 217 } 218 modelActivation.setJdk(activation.getJdk()); 219 if (activation.getOs() != null) { 220 ActivationOS os = new ActivationOS(); 221 os.setArch(activation.getOs().getArch()); 222 os.setFamily(activation.getOs().getFamily()); 223 os.setName(activation.getOs().getName()); 224 os.setVersion(activation.getOs().getVersion()); 225 modelActivation.setOs(os); 226 } 227 if (activation.getProperty() != null) { 228 ActivationProperty property = new ActivationProperty(); 229 property.setName(activation.getProperty().getName()); 230 property.setValue(activation.getProperty().getValue()); 231 modelActivation.setProperty(property); 232 } 233 return modelActivation; 234 } 235 236 public boolean getOffline() { 237 return this.offline; 238 } 239 240 public MirrorSelector getMirrorSelector() { 241 return this.mirrorSelector; 242 } 243 244 public AuthenticationSelector getAuthenticationSelector() { 245 return this.authenticationSelector; 246 } 247 248 public ProxySelector getProxySelector() { 249 return this.proxySelector; 250 } 251 252 public String getLocalRepository() { 253 return this.localRepository; 254 } 255 256 public List<Profile> getActiveProfiles() { 257 return this.activeProfiles; 258 } 259 260 private static final class SpringBootCliProfileActivationContext 261 implements ProfileActivationContext { 262 263 private final List<String> activeProfiles; 264 265 SpringBootCliProfileActivationContext(List<String> activeProfiles) { 266 this.activeProfiles = activeProfiles; 267 } 268 269 @Override 270 public List<String> getActiveProfileIds() { 271 return this.activeProfiles; 272 } 273 274 @Override 275 public List<String> getInactiveProfileIds() { 276 return Collections.emptyList(); 277 } 278 279 @SuppressWarnings({ "unchecked", "rawtypes" }) 280 @Override 281 public Map<String, String> getSystemProperties() { 282 return (Map) System.getProperties(); 283 } 284 285 @Override 286 public Map<String, String> getUserProperties() { 287 return Collections.emptyMap(); 288 } 289 290 @Override 291 public File getProjectDirectory() { 292 return new File("."); 293 } 294 295 @Override 296 public Map<String, String> getProjectProperties() { 297 return Collections.emptyMap(); 298 } 299 300 } 301 302 private static final class SpringBootCliModelProblemCollector 303 implements ModelProblemCollector { 304 305 private final List<ModelProblemCollectorRequest> problems = new ArrayList<>(); 306 307 @Override 308 public void add(ModelProblemCollectorRequest req) { 309 this.problems.add(req); 310 } 311 312 List<ModelProblemCollectorRequest> getProblems() { 313 return this.problems; 314 } 315 316 } 317 318}