1 package org.apache.maven.settings.building;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.io.StringWriter;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.inject.Inject;
31 import javax.inject.Named;
32 import javax.inject.Singleton;
33
34 import org.apache.maven.building.FileSource;
35 import org.apache.maven.building.Source;
36 import org.apache.maven.settings.Settings;
37 import org.apache.maven.settings.TrackableBase;
38 import org.apache.maven.settings.io.SettingsParseException;
39 import org.apache.maven.settings.io.SettingsReader;
40 import org.apache.maven.settings.io.SettingsWriter;
41 import org.apache.maven.settings.merge.MavenSettingsMerger;
42 import org.apache.maven.settings.validation.SettingsValidator;
43 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
44 import org.codehaus.plexus.interpolation.InterpolationException;
45 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
46 import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
47 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
48
49
50
51
52
53
54 @Named
55 @Singleton
56 public class DefaultSettingsBuilder
57 implements SettingsBuilder
58 {
59
60 private SettingsReader settingsReader;
61
62 private SettingsWriter settingsWriter;
63
64 private SettingsValidator settingsValidator;
65
66 private final MavenSettingsMerger settingsMerger = new MavenSettingsMerger();
67
68 @Inject
69 public DefaultSettingsBuilder( SettingsReader settingsReader,
70 SettingsWriter settingsWriter,
71 SettingsValidator settingsValidator )
72 {
73 this.settingsReader = settingsReader;
74 this.settingsWriter = settingsWriter;
75 this.settingsValidator = settingsValidator;
76 }
77
78 public DefaultSettingsBuilder setSettingsReader( SettingsReader settingsReader )
79 {
80 this.settingsReader = settingsReader;
81 return this;
82 }
83
84 public DefaultSettingsBuilder setSettingsWriter( SettingsWriter settingsWriter )
85 {
86 this.settingsWriter = settingsWriter;
87 return this;
88 }
89
90 public DefaultSettingsBuilder setSettingsValidator( SettingsValidator settingsValidator )
91 {
92 this.settingsValidator = settingsValidator;
93 return this;
94 }
95
96 @Override
97 public SettingsBuildingResult build( SettingsBuildingRequest request )
98 throws SettingsBuildingException
99 {
100 DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector( null );
101
102 Source globalSettingsSource =
103 getSettingsSource( request.getGlobalSettingsFile(), request.getGlobalSettingsSource() );
104 Settings globalSettings = readSettings( globalSettingsSource, request, problems );
105
106 Source userSettingsSource =
107 getSettingsSource( request.getUserSettingsFile(), request.getUserSettingsSource() );
108 Settings userSettings = readSettings( userSettingsSource, request, problems );
109
110 settingsMerger.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL );
111
112 problems.setSource( "" );
113
114 userSettings = interpolate( userSettings, request, problems );
115
116
117 String localRepository = userSettings.getLocalRepository();
118 if ( localRepository != null && localRepository.length() > 0 )
119 {
120 File file = new File( localRepository );
121 if ( !file.isAbsolute() && file.getPath().startsWith( File.separator ) )
122 {
123 userSettings.setLocalRepository( file.getAbsolutePath() );
124 }
125 }
126
127 if ( hasErrors( problems.getProblems() ) )
128 {
129 throw new SettingsBuildingException( problems.getProblems() );
130 }
131
132 return new DefaultSettingsBuildingResult( userSettings, problems.getProblems() );
133 }
134
135 private boolean hasErrors( List<SettingsProblem> problems )
136 {
137 if ( problems != null )
138 {
139 for ( SettingsProblem problem : problems )
140 {
141 if ( SettingsProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
142 {
143 return true;
144 }
145 }
146 }
147
148 return false;
149 }
150
151 private Source getSettingsSource( File settingsFile, Source settingsSource )
152 {
153 if ( settingsSource != null )
154 {
155 return settingsSource;
156 }
157 else if ( settingsFile != null && settingsFile.exists() )
158 {
159 return new FileSource( settingsFile );
160 }
161 return null;
162 }
163
164 private Settings readSettings( Source settingsSource, SettingsBuildingRequest request,
165 DefaultSettingsProblemCollector problems )
166 {
167 if ( settingsSource == null )
168 {
169 return new Settings();
170 }
171
172 problems.setSource( settingsSource.getLocation() );
173
174 Settings settings;
175
176 try
177 {
178 Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.TRUE );
179
180 try
181 {
182 settings = settingsReader.read( settingsSource.getInputStream(), options );
183 }
184 catch ( SettingsParseException e )
185 {
186 options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
187
188 settings = settingsReader.read( settingsSource.getInputStream(), options );
189
190 problems.add( SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
191 e );
192 }
193 }
194 catch ( SettingsParseException e )
195 {
196 problems.add( SettingsProblem.Severity.FATAL, "Non-parseable settings " + settingsSource.getLocation()
197 + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
198 return new Settings();
199 }
200 catch ( IOException e )
201 {
202 problems.add( SettingsProblem.Severity.FATAL, "Non-readable settings " + settingsSource.getLocation()
203 + ": " + e.getMessage(), -1, -1, e );
204 return new Settings();
205 }
206
207 settingsValidator.validate( settings, problems );
208
209 return settings;
210 }
211
212 private Settings interpolate( Settings settings, SettingsBuildingRequest request,
213 SettingsProblemCollector problems )
214 {
215 StringWriter writer = new StringWriter( 1024 * 4 );
216
217 try
218 {
219 settingsWriter.write( writer, null, settings );
220 }
221 catch ( IOException e )
222 {
223 throw new IllegalStateException( "Failed to serialize settings to memory", e );
224 }
225
226 String serializedSettings = writer.toString();
227
228 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
229
230 interpolator.addValueSource( new PropertiesBasedValueSource( request.getUserProperties() ) );
231
232 interpolator.addValueSource( new PropertiesBasedValueSource( request.getSystemProperties() ) );
233
234 try
235 {
236 interpolator.addValueSource( new EnvarBasedValueSource() );
237 }
238 catch ( IOException e )
239 {
240 problems.add( SettingsProblem.Severity.WARNING, "Failed to use environment variables for interpolation: "
241 + e.getMessage(), -1, -1, e );
242 }
243
244 interpolator.addPostProcessor( new InterpolationPostProcessor()
245 {
246 @Override
247 public Object execute( String expression, Object value )
248 {
249 if ( value != null )
250 {
251
252 value = value.toString().replace( "&", "&" ).replace( "<", "<" ).replace( ">", ">" );
253 return value;
254 }
255 return null;
256 }
257 } );
258
259 try
260 {
261 serializedSettings = interpolator.interpolate( serializedSettings, "settings" );
262 }
263 catch ( InterpolationException e )
264 {
265 problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
266 e );
267
268 return settings;
269 }
270
271 Settings result;
272 try
273 {
274 Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
275 result = settingsReader.read( new StringReader( serializedSettings ), options );
276 }
277 catch ( IOException e )
278 {
279 problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
280 e );
281 return settings;
282 }
283
284 return result;
285 }
286
287 }