View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.settings.building;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.File;
26  import java.io.IOException;
27  import java.io.StringReader;
28  import java.io.StringWriter;
29  import java.util.Collections;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.apache.maven.building.FileSource;
34  import org.apache.maven.building.Source;
35  import org.apache.maven.settings.Settings;
36  import org.apache.maven.settings.TrackableBase;
37  import org.apache.maven.settings.io.SettingsParseException;
38  import org.apache.maven.settings.io.SettingsReader;
39  import org.apache.maven.settings.io.SettingsWriter;
40  import org.apache.maven.settings.merge.MavenSettingsMerger;
41  import org.apache.maven.settings.validation.SettingsValidator;
42  import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
43  import org.codehaus.plexus.interpolation.InterpolationException;
44  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
45  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
46  import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
47  
48  /**
49   * Builds the effective settings from a user settings file and/or a global settings file.
50   *
51   * @deprecated since 4.0.0, use {@link org.apache.maven.api.services.SettingsBuilder} instead
52   */
53  @Named
54  @Singleton
55  @Deprecated(since = "4.0.0")
56  public class DefaultSettingsBuilder implements SettingsBuilder {
57  
58      private SettingsReader settingsReader;
59  
60      private SettingsWriter settingsWriter;
61  
62      private SettingsValidator settingsValidator;
63  
64      private final MavenSettingsMerger settingsMerger = new MavenSettingsMerger();
65  
66      @Inject
67      public DefaultSettingsBuilder(
68              SettingsReader settingsReader, SettingsWriter settingsWriter, SettingsValidator settingsValidator) {
69          this.settingsReader = settingsReader;
70          this.settingsWriter = settingsWriter;
71          this.settingsValidator = settingsValidator;
72      }
73  
74      public DefaultSettingsBuilder setSettingsReader(SettingsReader settingsReader) {
75          this.settingsReader = settingsReader;
76          return this;
77      }
78  
79      public DefaultSettingsBuilder setSettingsWriter(SettingsWriter settingsWriter) {
80          this.settingsWriter = settingsWriter;
81          return this;
82      }
83  
84      public DefaultSettingsBuilder setSettingsValidator(SettingsValidator settingsValidator) {
85          this.settingsValidator = settingsValidator;
86          return this;
87      }
88  
89      @Override
90      public SettingsBuildingResult build(SettingsBuildingRequest request) throws SettingsBuildingException {
91          DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector(null);
92  
93          Source globalSettingsSource =
94                  getSettingsSource(request.getGlobalSettingsFile(), request.getGlobalSettingsSource());
95          Settings globalSettings = readSettings(globalSettingsSource, request, problems);
96  
97          Source userSettingsSource = getSettingsSource(request.getUserSettingsFile(), request.getUserSettingsSource());
98          Settings userSettings = readSettings(userSettingsSource, request, problems);
99  
100         settingsMerger.merge(userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL);
101 
102         problems.setSource("");
103 
104         userSettings = interpolate(userSettings, request, problems);
105 
106         // for the special case of a drive-relative Windows path, make sure it's absolute to save plugins from trouble
107         String localRepository = userSettings.getLocalRepository();
108         if (localRepository != null && localRepository.length() > 0) {
109             File file = new File(localRepository);
110             if (!file.isAbsolute() && file.getPath().startsWith(File.separator)) {
111                 userSettings.setLocalRepository(file.getAbsolutePath());
112             }
113         }
114 
115         if (hasErrors(problems.getProblems())) {
116             throw new SettingsBuildingException(problems.getProblems());
117         }
118 
119         return new DefaultSettingsBuildingResult(userSettings, problems.getProblems());
120     }
121 
122     private boolean hasErrors(List<SettingsProblem> problems) {
123         if (problems != null) {
124             for (SettingsProblem problem : problems) {
125                 if (SettingsProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
126                     return true;
127                 }
128             }
129         }
130 
131         return false;
132     }
133 
134     private Source getSettingsSource(File settingsFile, Source settingsSource) {
135         if (settingsSource != null) {
136             return settingsSource;
137         } else if (settingsFile != null && settingsFile.exists()) {
138             return new FileSource(settingsFile);
139         }
140         return null;
141     }
142 
143     private Settings readSettings(
144             Source settingsSource, SettingsBuildingRequest request, DefaultSettingsProblemCollector problems) {
145         if (settingsSource == null) {
146             return new Settings();
147         }
148 
149         problems.setSource(settingsSource.getLocation());
150 
151         Settings settings;
152 
153         try {
154             Map<String, ?> options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.TRUE);
155 
156             try {
157                 settings = settingsReader.read(settingsSource.getInputStream(), options);
158             } catch (SettingsParseException e) {
159                 options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE);
160 
161                 settings = settingsReader.read(settingsSource.getInputStream(), options);
162 
163                 problems.add(
164                         SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e);
165             }
166         } catch (SettingsParseException e) {
167             problems.add(
168                     SettingsProblem.Severity.FATAL,
169                     "Non-parseable settings " + settingsSource.getLocation() + ": " + e.getMessage(),
170                     e.getLineNumber(),
171                     e.getColumnNumber(),
172                     e);
173             return new Settings();
174         } catch (IOException e) {
175             problems.add(
176                     SettingsProblem.Severity.FATAL,
177                     "Non-readable settings " + settingsSource.getLocation() + ": " + e.getMessage(),
178                     -1,
179                     -1,
180                     e);
181             return new Settings();
182         }
183 
184         settingsValidator.validate(settings, problems);
185 
186         return settings;
187     }
188 
189     private Settings interpolate(
190             Settings settings, SettingsBuildingRequest request, SettingsProblemCollector problems) {
191         StringWriter writer = new StringWriter(1024 * 4);
192 
193         try {
194             settingsWriter.write(writer, null, settings);
195         } catch (IOException e) {
196             throw new IllegalStateException("Failed to serialize settings to memory", e);
197         }
198 
199         String serializedSettings = writer.toString();
200 
201         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
202 
203         interpolator.addValueSource(new PropertiesBasedValueSource(request.getUserProperties()));
204 
205         interpolator.addValueSource(new PropertiesBasedValueSource(request.getSystemProperties()));
206 
207         try {
208             interpolator.addValueSource(new EnvarBasedValueSource());
209         } catch (IOException e) {
210             problems.add(
211                     SettingsProblem.Severity.WARNING,
212                     "Failed to use environment variables for interpolation: " + e.getMessage(),
213                     -1,
214                     -1,
215                     e);
216         }
217 
218         interpolator.addPostProcessor(new InterpolationPostProcessor() {
219             @Override
220             public Object execute(String expression, Object value) {
221                 if (value != null) {
222                     // we're going to parse this back in as XML so we need to escape XML markup
223                     value = value.toString()
224                             .replace("&", "&amp;")
225                             .replace("<", "&lt;")
226                             .replace(">", "&gt;");
227                     return value;
228                 }
229                 return null;
230             }
231         });
232 
233         try {
234             serializedSettings = interpolator.interpolate(serializedSettings, "settings");
235         } catch (InterpolationException e) {
236             problems.add(
237                     SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1, e);
238 
239             return settings;
240         }
241 
242         Settings result;
243         try {
244             Map<String, ?> options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE);
245             result = settingsReader.read(new StringReader(serializedSettings), options);
246         } catch (IOException e) {
247             problems.add(
248                     SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1, e);
249             return settings;
250         }
251 
252         return result;
253     }
254 }