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.toolchain.building;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.IOException;
26  import java.io.StringReader;
27  import java.io.StringWriter;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.maven.building.Problem;
33  import org.apache.maven.building.ProblemCollector;
34  import org.apache.maven.building.ProblemCollectorFactory;
35  import org.apache.maven.building.Source;
36  import org.apache.maven.toolchain.io.ToolchainsParseException;
37  import org.apache.maven.toolchain.io.ToolchainsReader;
38  import org.apache.maven.toolchain.io.ToolchainsWriter;
39  import org.apache.maven.toolchain.merge.MavenToolchainMerger;
40  import org.apache.maven.toolchain.model.PersistedToolchains;
41  import org.apache.maven.toolchain.model.TrackableBase;
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.RegexBasedInterpolator;
46  
47  /**
48   *
49   * @since 3.3.0
50   * @deprecated since 4.0.0, use {@code org.apache.maven.api.services.ToolchainsBuilder} instead
51   */
52  @Named
53  @Singleton
54  @Deprecated(since = "4.0.0")
55  public class DefaultToolchainsBuilder implements ToolchainsBuilder {
56      private MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger();
57  
58      @Inject
59      private ToolchainsWriter toolchainsWriter;
60  
61      @Inject
62      private ToolchainsReader toolchainsReader;
63  
64      @Override
65      public ToolchainsBuildingResult build(ToolchainsBuildingRequest request) throws ToolchainsBuildingException {
66          ProblemCollector problems = ProblemCollectorFactory.newInstance(null);
67  
68          PersistedToolchains globalToolchains = readToolchains(request.getGlobalToolchainsSource(), request, problems);
69  
70          PersistedToolchains userToolchains = readToolchains(request.getUserToolchainsSource(), request, problems);
71  
72          toolchainsMerger.merge(userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL);
73  
74          problems.setSource("");
75  
76          userToolchains = interpolate(userToolchains, problems);
77  
78          if (hasErrors(problems.getProblems())) {
79              throw new ToolchainsBuildingException(problems.getProblems());
80          }
81  
82          return new DefaultToolchainsBuildingResult(userToolchains, problems.getProblems());
83      }
84  
85      private PersistedToolchains interpolate(PersistedToolchains toolchains, ProblemCollector problems) {
86  
87          StringWriter stringWriter = new StringWriter(1024 * 4);
88          try {
89              toolchainsWriter.write(stringWriter, null, toolchains);
90          } catch (IOException e) {
91              throw new IllegalStateException("Failed to serialize toolchains to memory", e);
92          }
93  
94          String serializedToolchains = stringWriter.toString();
95  
96          RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
97  
98          try {
99              interpolator.addValueSource(new EnvarBasedValueSource());
100         } catch (IOException e) {
101             problems.add(
102                     Problem.Severity.WARNING,
103                     "Failed to use environment variables for interpolation: " + e.getMessage(),
104                     -1,
105                     -1,
106                     e);
107         }
108 
109         interpolator.addPostProcessor(new InterpolationPostProcessor() {
110             @Override
111             public Object execute(String expression, Object value) {
112                 if (value != null) {
113                     // we're going to parse this back in as XML so we need to escape XML markup
114                     value = value.toString()
115                             .replace("&", "&")
116                             .replace("<", "&lt;")
117                             .replace(">", "&gt;");
118                     return value;
119                 }
120                 return null;
121             }
122         });
123 
124         try {
125             serializedToolchains = interpolator.interpolate(serializedToolchains);
126         } catch (InterpolationException e) {
127             problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
128             return toolchains;
129         }
130 
131         PersistedToolchains result;
132         try {
133             Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
134 
135             result = toolchainsReader.read(new StringReader(serializedToolchains), options);
136         } catch (IOException e) {
137             problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
138             return toolchains;
139         }
140 
141         return result;
142     }
143 
144     private PersistedToolchains readToolchains(
145             Source toolchainsSource, ToolchainsBuildingRequest request, ProblemCollector problems) {
146         if (toolchainsSource == null) {
147             return new PersistedToolchains();
148         }
149 
150         PersistedToolchains toolchains;
151 
152         try {
153             Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.TRUE);
154 
155             try {
156                 toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
157             } catch (ToolchainsParseException e) {
158                 options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
159 
160                 toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
161 
162                 problems.add(Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e);
163             }
164         } catch (ToolchainsParseException e) {
165             problems.add(
166                     Problem.Severity.FATAL,
167                     "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
168                     e.getLineNumber(),
169                     e.getColumnNumber(),
170                     e);
171             return new PersistedToolchains();
172         } catch (IOException e) {
173             problems.add(
174                     Problem.Severity.FATAL,
175                     "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
176                     -1,
177                     -1,
178                     e);
179             return new PersistedToolchains();
180         }
181 
182         return toolchains;
183     }
184 
185     private boolean hasErrors(List<Problem> problems) {
186         if (problems != null) {
187             for (Problem problem : problems) {
188                 if (Problem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
189                     return true;
190                 }
191             }
192         }
193 
194         return false;
195     }
196 }