View Javadoc
1   package org.apache.maven.toolchain.building;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.building.Problem;
23  import org.apache.maven.building.ProblemCollector;
24  import org.apache.maven.building.ProblemCollectorFactory;
25  import org.apache.maven.building.Source;
26  import org.apache.maven.toolchain.io.ToolchainsParseException;
27  import org.apache.maven.toolchain.io.ToolchainsReader;
28  import org.apache.maven.toolchain.io.ToolchainsWriter;
29  import org.apache.maven.toolchain.merge.MavenToolchainMerger;
30  import org.apache.maven.toolchain.model.PersistedToolchains;
31  import org.apache.maven.toolchain.model.TrackableBase;
32  import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
33  import org.codehaus.plexus.interpolation.InterpolationException;
34  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
35  import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
36  
37  import javax.inject.Inject;
38  import javax.inject.Named;
39  import javax.inject.Singleton;
40  import java.io.IOException;
41  import java.io.StringReader;
42  import java.io.StringWriter;
43  import java.util.Collections;
44  import java.util.List;
45  import java.util.Map;
46  
47  /**
48   * 
49   * @author Robert Scholte
50   * @since 3.3.0
51   */
52  @Named
53  @Singleton
54  public class DefaultToolchainsBuilder
55      implements ToolchainsBuilder
56  {
57      private MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger();
58  
59      @Inject
60      private ToolchainsWriter toolchainsWriter;
61  
62      @Inject
63      private ToolchainsReader toolchainsReader;
64  
65      @Override
66      public ToolchainsBuildingResult build( ToolchainsBuildingRequest request )
67          throws ToolchainsBuildingException
68      {
69          ProblemCollector problems = ProblemCollectorFactory.newInstance( null );
70          
71          PersistedToolchains globalToolchains = readToolchains( request.getGlobalToolchainsSource(), request, problems );
72  
73          PersistedToolchains userToolchains = readToolchains( request.getUserToolchainsSource(), request, problems );
74  
75          toolchainsMerger.merge( userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL );
76          
77          problems.setSource( "" );
78  
79          userToolchains = interpolate( userToolchains, problems );
80  
81          if ( hasErrors( problems.getProblems() ) )
82          {
83              throw new ToolchainsBuildingException( problems.getProblems() );
84          }
85  
86  
87          return new DefaultToolchainsBuildingResult( userToolchains, problems.getProblems() );
88      }
89  
90      private PersistedToolchains interpolate( PersistedToolchains toolchains, ProblemCollector problems )
91      {
92  
93          StringWriter stringWriter = new StringWriter( 1024 * 4 );
94          try
95          {
96              toolchainsWriter.write( stringWriter, null, toolchains );
97          }
98          catch ( IOException e )
99          {
100             throw new IllegalStateException( "Failed to serialize toolchains to memory", e );
101         }
102 
103         String serializedToolchains = stringWriter.toString();
104 
105         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
106 
107         try
108         {
109             interpolator.addValueSource( new EnvarBasedValueSource() );
110         }
111         catch ( IOException e )
112         {
113             problems.add( Problem.Severity.WARNING, "Failed to use environment variables for interpolation: "
114                     + e.getMessage(), -1, -1, e );
115         }
116 
117         interpolator.addPostProcessor( new InterpolationPostProcessor()
118         {
119             @Override
120             public Object execute( String expression, Object value )
121             {
122                 if ( value != null )
123                 {
124                     // we're going to parse this back in as XML so we need to escape XML markup
125                     value = value.toString().replace( "&", "&amp;" ).replace( "<", "&lt;" ).replace( ">", "&gt;" );
126                     return value;
127                 }
128                 return null;
129             }
130         } );
131 
132         try
133         {
134             serializedToolchains = interpolator.interpolate( serializedToolchains );
135         }
136         catch ( InterpolationException e )
137         {
138             problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
139             return toolchains;
140         }
141 
142         PersistedToolchains result;
143         try
144         {
145             Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
146 
147             result = toolchainsReader.read( new StringReader( serializedToolchains ), options );
148         }
149         catch ( IOException e )
150         {
151             problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
152             return toolchains;
153         }
154 
155         return result;
156     }
157 
158     private PersistedToolchains readToolchains( Source toolchainsSource, ToolchainsBuildingRequest request,
159                                                 ProblemCollector problems )
160     {
161         if ( toolchainsSource == null )
162         {
163             return new PersistedToolchains();
164         }
165 
166         PersistedToolchains toolchains;
167 
168         try
169         {
170             Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.TRUE );
171 
172             try
173             {
174                 toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
175             }
176             catch ( ToolchainsParseException e )
177             {
178                 options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
179 
180                 toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
181 
182                 problems.add( Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
183                               e );
184             }
185         }
186         catch ( ToolchainsParseException e )
187         {
188             problems.add( Problem.Severity.FATAL, "Non-parseable toolchains " + toolchainsSource.getLocation()
189                 + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
190             return new PersistedToolchains();
191         }
192         catch ( IOException e )
193         {
194             problems.add( Problem.Severity.FATAL, "Non-readable toolchains " + toolchainsSource.getLocation()
195                 + ": " + e.getMessage(), -1, -1, e );
196             return new PersistedToolchains();
197         }
198 
199         return toolchains;
200     }
201     
202     private boolean hasErrors( List<Problem> problems )
203     {
204         if ( problems != null )
205         {
206             for ( Problem problem : problems )
207             {
208                 if ( Problem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
209                 {
210                     return true;
211                 }
212             }
213         }
214 
215         return false;
216     }
217 }