View Javadoc

1   package org.apache.maven.plugin;
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 java.io.File;
23  import java.util.Properties;
24  
25  import org.apache.maven.execution.MavenSession;
26  import org.apache.maven.plugin.descriptor.MojoDescriptor;
27  import org.apache.maven.plugin.descriptor.PluginDescriptor;
28  import org.apache.maven.project.MavenProject;
29  import org.apache.maven.project.path.PathTranslator;
30  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
31  import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
32  import org.codehaus.plexus.logging.Logger;
33  import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
34  
35  /**
36   * @author Jason van Zyl
37   */
38  public class PluginParameterExpressionEvaluator
39      implements TypeAwareExpressionEvaluator
40  {
41      private MavenSession session;
42  
43      private MojoExecution mojoExecution;
44  
45      private MavenProject project;
46  
47      private String basedir;
48  
49      private Properties properties;
50  
51      @Deprecated //TODO: used by the Enforcer plugin
52      public PluginParameterExpressionEvaluator( MavenSession session, MojoExecution mojoExecution,
53                                                 PathTranslator pathTranslator, Logger logger, MavenProject project,
54                                                 Properties properties )
55      {
56          this( session, mojoExecution );
57      }
58  
59      public PluginParameterExpressionEvaluator( MavenSession session )
60      {
61          this( session, null );
62      }
63  
64      public PluginParameterExpressionEvaluator( MavenSession session, MojoExecution mojoExecution )
65      {
66          this.session = session;
67          this.mojoExecution = mojoExecution;
68          this.properties = session.getExecutionProperties();
69          this.project = session.getCurrentProject();
70  
71          String basedir = null;
72  
73          if ( project != null )
74          {
75              File projectFile = project.getBasedir();
76  
77              // this should always be the case for non-super POM instances...
78              if ( projectFile != null )
79              {
80                  basedir = projectFile.getAbsolutePath();
81              }
82          }
83  
84          if ( ( basedir == null ) && ( session != null ) )
85          {
86              basedir = session.getExecutionRootDirectory();
87          }
88  
89          if ( basedir == null )
90          {
91              basedir = System.getProperty( "user.dir" );
92          }
93  
94          this.basedir = basedir;
95      }
96  
97      public Object evaluate( String expr )
98          throws ExpressionEvaluationException
99      {
100         return evaluate( expr, null );
101     }
102 
103     public Object evaluate( String expr, Class<?> type )
104         throws ExpressionEvaluationException
105     {
106         Object value = null;
107 
108         if ( expr == null )
109         {
110             return null;
111         }
112 
113         String expression = stripTokens( expr );
114         if ( expression.equals( expr ) )
115         {
116             int index = expr.indexOf( "${" );
117             if ( index >= 0 )
118             {
119                 int lastIndex = expr.indexOf( "}", index );
120                 if ( lastIndex >= 0 )
121                 {
122                     String retVal = expr.substring( 0, index );
123 
124                     if ( ( index > 0 ) && ( expr.charAt( index - 1 ) == '$' ) )
125                     {
126                         retVal += expr.substring( index + 1, lastIndex + 1 );
127                     }
128                     else
129                     {
130                         Object subResult = evaluate( expr.substring( index, lastIndex + 1 ) );
131 
132                         if ( subResult != null )
133                         {
134                             retVal += subResult;
135                         }
136                         else
137                         {
138                             retVal += "$" + expr.substring( index + 1, lastIndex + 1 );
139                         }
140                     }
141 
142                     retVal += evaluate( expr.substring( lastIndex + 1 ) );
143                     return retVal;
144                 }
145             }
146 
147             // Was not an expression
148             if ( expression.indexOf( "$$" ) > -1 )
149             {
150                 return expression.replaceAll( "\\$\\$", "\\$" );
151             }
152             else
153             {
154                 return expression;
155             }
156         }
157 
158         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
159 
160         if ( "localRepository".equals( expression ) )
161         {
162             value = session.getLocalRepository();
163         }
164         else if ( "session".equals( expression ) )
165         {
166             value = session;
167         }
168         else if ( expression.startsWith( "session" ) )
169         {
170             try
171             {
172                 int pathSeparator = expression.indexOf( "/" );
173 
174                 if ( pathSeparator > 0 )
175                 {
176                     String pathExpression = expression.substring( 1, pathSeparator );
177                     value = ReflectionValueExtractor.evaluate( pathExpression, session );
178                     value = value + expression.substring( pathSeparator );
179                 }
180                 else
181                 {
182                     value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), session );
183                 }
184             }
185             catch ( Exception e )
186             {
187                 // TODO: don't catch exception
188                 throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
189                                                          e );
190             }
191         }
192         else if ( "reactorProjects".equals( expression ) )
193         {
194             value = session.getProjects();
195         }
196         else if ( "mojoExecution".equals( expression ) )
197         {
198             value = mojoExecution;
199         }
200         else if ( "project".equals( expression ) )
201         {
202             value = project;
203         }
204         else if ( "executedProject".equals( expression ) )
205         {
206             value = project.getExecutionProject();
207         }
208         else if ( expression.startsWith( "project" ) || expression.startsWith( "pom" ) )
209         {
210             try
211             {
212                 int pathSeparator = expression.indexOf( "/" );
213 
214                 if ( pathSeparator > 0 )
215                 {
216                     String pathExpression = expression.substring( 0, pathSeparator );
217                     value = ReflectionValueExtractor.evaluate( pathExpression, project );
218                     value = value + expression.substring( pathSeparator );
219                 }
220                 else
221                 {
222                     value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), project );
223                 }
224             }
225             catch ( Exception e )
226             {
227                 // TODO: don't catch exception
228                 throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
229                                                          e );
230             }
231         }
232         else if ( expression.equals( "repositorySystemSession" ) )
233         {
234             value = session.getRepositorySession();
235         }
236         else if ( expression.equals( "mojo" ) )
237         {
238             value = mojoExecution;
239         }
240         else if ( expression.startsWith( "mojo" ) )
241         {
242             try
243             {
244                 int pathSeparator = expression.indexOf( "/" );
245 
246                 if ( pathSeparator > 0 )
247                 {
248                     String pathExpression = expression.substring( 1, pathSeparator );
249                     value = ReflectionValueExtractor.evaluate( pathExpression, mojoExecution );
250                     value = value + expression.substring( pathSeparator );
251                 }
252                 else
253                 {
254                     value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), mojoExecution );
255                 }
256             }
257             catch ( Exception e )
258             {
259                 // TODO: don't catch exception
260                 throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
261                                                          e );
262             }
263         }
264         else if ( expression.equals( "plugin" ) )
265         {
266             value = mojoDescriptor.getPluginDescriptor();
267         }
268         else if ( expression.startsWith( "plugin" ) )
269         {
270             try
271             {
272                 int pathSeparator = expression.indexOf( "/" );
273 
274                 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
275 
276                 if ( pathSeparator > 0 )
277                 {
278                     String pathExpression = expression.substring( 1, pathSeparator );
279                     value = ReflectionValueExtractor.evaluate( pathExpression, pluginDescriptor );
280                     value = value + expression.substring( pathSeparator );
281                 }
282                 else
283                 {
284                     value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), pluginDescriptor );
285                 }
286             }
287             catch ( Exception e )
288             {
289                 throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
290                                                          e );
291             }
292         }
293         else if ( "settings".equals( expression ) )
294         {
295             value = session.getSettings();
296         }
297         else if ( expression.startsWith( "settings" ) )
298         {
299             try
300             {
301                 int pathSeparator = expression.indexOf( "/" );
302 
303                 if ( pathSeparator > 0 )
304                 {
305                     String pathExpression = expression.substring( 1, pathSeparator );
306                     value = ReflectionValueExtractor.evaluate( pathExpression, session.getSettings() );
307                     value = value + expression.substring( pathSeparator );
308                 }
309                 else
310                 {
311                     value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), session.getSettings() );
312                 }
313             }
314             catch ( Exception e )
315             {
316                 // TODO: don't catch exception
317                 throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
318                                                          e );
319             }
320         }
321         else if ( "basedir".equals( expression ) )
322         {
323             value = basedir;
324         }
325         else if ( expression.startsWith( "basedir" ) )
326         {
327             int pathSeparator = expression.indexOf( "/" );
328 
329             if ( pathSeparator > 0 )
330             {
331                 value = basedir + expression.substring( pathSeparator );
332             }
333         }
334 
335         /*
336          * MNG-4312: We neither have reserved all of the above magic expressions nor is their set fixed/well-known (it
337          * gets occasionally extended by newer Maven versions). This imposes the risk for existing plugins to
338          * unintentionally use such a magic expression for an ordinary system property. So here we check whether we
339          * ended up with a magic value that is not compatible with the type of the configured mojo parameter (a string
340          * could still be converted by the configurator so we leave those alone). If so, back off to evaluating the
341          * expression from properties only.
342          */
343         if ( value != null && type != null && !( value instanceof String ) && !isTypeCompatible( type, value ) )
344         {
345             value = null;
346         }
347 
348         if ( value == null )
349         {
350             // The CLI should win for defining properties
351 
352             if ( ( value == null ) && ( properties != null ) )
353             {
354                 // We will attempt to get nab a system property as a way to specify a
355                 // parameter to a plugins. My particular case here is allowing the surefire
356                 // plugin to run a single test so I want to specify that class on the cli
357                 // as a parameter.
358 
359                 value = properties.getProperty( expression );
360             }
361 
362             if ( ( value == null ) && ( ( project != null ) && ( project.getProperties() != null ) ) )
363             {
364                 value = project.getProperties().getProperty( expression );
365             }
366 
367         }
368 
369         if ( value instanceof String )
370         {
371             // TODO: without #, this could just be an evaluate call...
372 
373             String val = (String) value;
374 
375             int exprStartDelimiter = val.indexOf( "${" );
376 
377             if ( exprStartDelimiter >= 0 )
378             {
379                 if ( exprStartDelimiter > 0 )
380                 {
381                     value = val.substring( 0, exprStartDelimiter ) + evaluate( val.substring( exprStartDelimiter ) );
382                 }
383                 else
384                 {
385                     value = evaluate( val.substring( exprStartDelimiter ) );
386                 }
387             }
388         }
389 
390         return value;
391     }
392 
393     private static boolean isTypeCompatible( Class<?> type, Object value )
394     {
395         if ( type.isInstance( value ) )
396         {
397             return true;
398         }
399         // likely Boolean -> boolean, Short -> int etc. conversions, it's not the problem case we try to avoid
400         return ( ( type.isPrimitive() || type.getName().startsWith( "java.lang." ) )
401                         && value.getClass().getName().startsWith( "java.lang." ) );
402     }
403 
404     private String stripTokens( String expr )
405     {
406         if ( expr.startsWith( "${" ) && ( expr.indexOf( "}" ) == expr.length() - 1 ) )
407         {
408             expr = expr.substring( 2, expr.length() - 1 );
409         }
410         return expr;
411     }
412 
413     public File alignToBaseDirectory( File file )
414     {
415         // TODO: Copied from the DefaultInterpolator. We likely want to resurrect the PathTranslator or at least a
416         // similar component for re-usage
417         if ( file != null )
418         {
419             if ( file.isAbsolute() )
420             {
421                 // path was already absolute, just normalize file separator and we're done
422             }
423             else if ( file.getPath().startsWith( File.separator ) )
424             {
425                 // drive-relative Windows path, don't align with project directory but with drive root
426                 file = file.getAbsoluteFile();
427             }
428             else
429             {
430                 // an ordinary relative path, align with project directory
431                 file = new File( new File( basedir, file.getPath() ).toURI().normalize() ).getAbsoluteFile();
432             }
433         }
434         return file;
435     }
436 
437 }