View Javadoc
1   package org.apache.maven.plugin.toolchain;
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.execution.MavenSession;
23  import org.apache.maven.plugin.AbstractMojo;
24  import org.apache.maven.plugin.MojoExecutionException;
25  import org.apache.maven.plugin.MojoFailureException;
26  import org.apache.maven.plugins.annotations.Component;
27  import org.apache.maven.plugins.annotations.LifecyclePhase;
28  import org.apache.maven.plugins.annotations.Mojo;
29  import org.apache.maven.plugins.annotations.Parameter;
30  import org.apache.maven.toolchain.MisconfiguredToolchainException;
31  import org.apache.maven.toolchain.ToolchainManagerPrivate;
32  import org.apache.maven.toolchain.ToolchainPrivate;
33  
34  import java.lang.reflect.InvocationTargetException;
35  import java.lang.reflect.Method;
36  import java.util.ArrayList;
37  import java.util.List;
38  import java.util.Map;
39  
40  /**
41   * Check that toolchains requirements are met by currently configured toolchains and
42   * store the selected toolchains in build context for later retrieval by other plugins.
43   *
44   * @author mkleint
45   */
46  @Mojo( name = "toolchain", defaultPhase = LifecyclePhase.VALIDATE,
47         configurator = "toolchains-requirement-configurator" )
48  public class ToolchainMojo
49      extends AbstractMojo
50  {
51  
52      /**
53       */
54      @Component
55      private ToolchainManagerPrivate toolchainManagerPrivate;
56  
57      /**
58       * The current build session instance. This is used for toolchain manager API calls.
59       */
60      @Parameter( defaultValue = "${session}", readonly = true, required = true )
61      private MavenSession session;
62  
63      /**
64       * Toolchains requirements, specified by one
65       * <pre>  &lt;toolchain-type&gt;
66       *    &lt;param&gt;expected value&lt;/param&gt;
67       *    ...
68       *  &lt;/toolchain-type&gt;</pre>
69       * element for each required toolchain.
70       */
71      @Parameter( required = true )
72      private ToolchainsRequirement toolchains;
73  
74      public void execute()
75          throws MojoExecutionException, MojoFailureException
76      {
77          if ( toolchains == null )
78          {
79              // should not happen since parameter is required...
80              getLog().warn( "No toolchains requirements configured." );
81              return;
82          }
83  
84          List<String> nonMatchedTypes = new ArrayList<String>();
85  
86          for ( Map.Entry<String, Map<String, String>> entry : toolchains.getToolchains().entrySet() )
87          {
88              String type = entry.getKey();
89  
90              if ( !selectToolchain( type, entry.getValue() ) )
91              {
92                  nonMatchedTypes.add( type );
93              }
94          }
95  
96          if ( !nonMatchedTypes.isEmpty() )
97          {
98              // TODO add the default toolchain instance if defined??
99              StringBuilder buff = new StringBuilder();
100             buff.append( "Cannot find matching toolchain definitions for the following toolchain types:" );
101 
102             for ( String type : nonMatchedTypes )
103             {
104                 buff.append( '\n' );
105                 buff.append( getToolchainRequirementAsString( type, toolchains.getParams( type ) ) );
106             }
107 
108             getLog().error( buff.toString() );
109 
110             throw new MojoFailureException( buff.toString()
111                 + "\nPlease make sure you define the required toolchains in your ~/.m2/toolchains.xml file." );
112         }
113     }
114 
115     protected String getToolchainRequirementAsString( String type, Map<String, String> params )
116     {
117         StringBuilder buff = new StringBuilder();
118 
119         buff.append( type ).append( " [" );
120 
121         if ( params.size() == 0 )
122         {
123             buff.append( " any" );
124         }
125         else
126         {
127             for ( Map.Entry<String, String> param : params.entrySet() )
128             {
129                 buff.append( " " ).append( param.getKey() ).append( "='" ).append( param.getValue() );
130                 buff.append( "'" );
131             }
132         }
133 
134         buff.append( " ]" );
135 
136         return buff.toString();
137     }
138 
139     protected boolean selectToolchain( String type, Map<String, String> params )
140         throws MojoExecutionException
141     {
142         getLog().info( "Required toolchain: " + getToolchainRequirementAsString( type, params ) );
143         int typeFound = 0;
144 
145         try
146         {
147             ToolchainPrivate[] tcs = getToolchains( type );
148 
149             for ( ToolchainPrivate tc : tcs )
150             {
151                 if ( !type.equals( tc.getType() ) )
152                 {
153                     // useful because of MNG-5716
154                     continue;
155                 }
156 
157                 typeFound++;
158 
159                 if ( tc.matchesRequirements( params ) )
160                 {
161                     getLog().info( "Found matching toolchain for type " + type + ": " + tc );
162 
163                     // store matching toolchain to build context
164                     toolchainManagerPrivate.storeToolchainToBuildContext( tc, session );
165 
166                     return true;
167                 }
168             }
169         }
170         catch ( MisconfiguredToolchainException ex )
171         {
172             throw new MojoExecutionException( "Misconfigured toolchains.", ex );
173         }
174 
175         getLog().error( "No toolchain " + ( ( typeFound == 0 ) ? "found" : ( "matched from " + typeFound + " found" ) )
176                             + " for type " + type );
177 
178         return false;
179     }
180 
181     private ToolchainPrivate[] getToolchains( String type )
182         throws MojoExecutionException, MisconfiguredToolchainException
183     {
184         Class<?> managerClass = toolchainManagerPrivate.getClass();
185 
186         try
187         {
188             try
189             {
190                 // try 3.x style API
191                 Method newMethod =
192                     managerClass.getMethod( "getToolchainsForType", new Class[] { String.class, MavenSession.class } );
193 
194                 return (ToolchainPrivate[]) newMethod.invoke( toolchainManagerPrivate, type, session );
195             }
196             catch ( NoSuchMethodException e )
197             {
198                 // try 2.x style API
199                 Method oldMethod = managerClass.getMethod( "getToolchainsForType", new Class[] { String.class } );
200 
201                 return (ToolchainPrivate[]) oldMethod.invoke( toolchainManagerPrivate, type );
202             }
203         }
204         catch ( NoSuchMethodException e )
205         {
206             throw new MojoExecutionException( "Incompatible toolchain API", e );
207         }
208         catch ( IllegalAccessException e )
209         {
210             throw new MojoExecutionException( "Incompatible toolchain API", e );
211         }
212         catch ( InvocationTargetException e )
213         {
214             Throwable cause = e.getCause();
215 
216             if ( cause instanceof RuntimeException )
217             {
218                 throw (RuntimeException) cause;
219             }
220             if ( cause instanceof MisconfiguredToolchainException )
221             {
222                 throw (MisconfiguredToolchainException) cause;
223             }
224 
225             throw new MojoExecutionException( "Incompatible toolchain API", e );
226         }
227     }
228 
229 }