1 package org.apache.maven.plugins.help;
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.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringWriter;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.TreeMap;
33 import java.util.jar.JarEntry;
34 import java.util.jar.JarInputStream;
35
36 import org.apache.commons.lang.ClassUtils;
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.ArtifactUtils;
39 import org.apache.maven.artifact.factory.ArtifactFactory;
40 import org.apache.maven.artifact.repository.ArtifactRepository;
41 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
42 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
43 import org.apache.maven.artifact.resolver.ArtifactResolver;
44 import org.apache.maven.execution.MavenSession;
45 import org.apache.maven.model.Dependency;
46 import org.apache.maven.model.Model;
47 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
48 import org.apache.maven.plugin.AbstractMojo;
49 import org.apache.maven.plugin.MojoExecution;
50 import org.apache.maven.plugin.MojoExecutionException;
51 import org.apache.maven.plugin.MojoFailureException;
52 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
53 import org.apache.maven.plugin.descriptor.MojoDescriptor;
54 import org.apache.maven.project.MavenProject;
55 import org.apache.maven.project.MavenProjectBuilder;
56 import org.apache.maven.project.ProjectBuildingException;
57 import org.apache.maven.project.path.PathTranslator;
58 import org.apache.maven.settings.Settings;
59 import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
60 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
61 import org.codehaus.plexus.components.interactivity.InputHandler;
62 import org.codehaus.plexus.util.IOUtil;
63 import org.codehaus.plexus.util.StringUtils;
64
65 import com.thoughtworks.xstream.XStream;
66 import com.thoughtworks.xstream.converters.MarshallingContext;
67 import com.thoughtworks.xstream.converters.collections.PropertiesConverter;
68 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
69
70
71
72
73
74
75
76
77
78
79 public class EvaluateMojo
80 extends AbstractMojo
81 {
82
83
84
85
86
87
88
89
90
91 private ArtifactFactory artifactFactory;
92
93
94
95
96
97
98 private InputHandler inputHandler;
99
100
101
102
103
104
105 private MavenProjectBuilder mavenProjectBuilder;
106
107
108
109
110 private PathTranslator pathTranslator;
111
112
113
114
115
116
117 private ArtifactResolver resolver;
118
119
120
121
122 private LoggerRetriever loggerRetriever;
123
124
125
126
127
128
129
130
131
132
133
134
135 private String artifact;
136
137
138
139
140
141
142 private String expression;
143
144
145
146
147
148
149
150
151 protected ArtifactRepository localRepository;
152
153
154
155
156
157
158
159
160 protected MavenProject project;
161
162
163
164
165
166
167
168
169 private List remoteRepositories;
170
171
172
173
174
175
176
177
178 protected Settings settings;
179
180
181
182
183
184
185
186
187 private MavenSession session;
188
189
190
191
192
193
194 private PluginParameterExpressionEvaluator evaluator;
195
196
197 private XStream xstream;
198
199
200
201
202
203
204 public void execute()
205 throws MojoExecutionException, MojoFailureException
206 {
207 if ( expression == null && !settings.isInteractiveMode() )
208 {
209 StringBuffer msg = new StringBuffer();
210 msg.append( "Maven is configured to NOT interact with the user for input. " );
211 msg.append( "This Mojo requires that 'interactiveMode' in your settings file is flag to 'true'." );
212
213 getLog().error( msg.toString() );
214 return;
215 }
216
217 validateParameters();
218
219 if ( StringUtils.isNotEmpty( artifact ) )
220 {
221 Artifact artifactObj = getArtifact( artifact );
222
223 try
224 {
225 project = getMavenProject( artifactObj );
226 }
227 catch ( ProjectBuildingException e )
228 {
229 throw new MojoExecutionException( "Unable to get the POM for the artifact '" + artifact
230 + "'. Verify the artifact parameter." );
231 }
232 }
233
234 if ( expression == null )
235 {
236 while ( true )
237 {
238 getLog().info( "Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:" );
239
240 try
241 {
242 String userExpression = inputHandler.readLine();
243 if ( userExpression == null || userExpression.toLowerCase( Locale.ENGLISH ).equals( "0" ) )
244 {
245 break;
246 }
247
248 handleResponse( userExpression );
249 }
250 catch ( IOException e )
251 {
252 throw new MojoExecutionException( "Unable to read from standard input.", e );
253 }
254 }
255 }
256 else
257 {
258 handleResponse( "${" + expression + "}" );
259 }
260 }
261
262
263
264
265
266
267
268
269 private void validateParameters()
270 {
271 if ( artifact == null )
272 {
273
274 getLog().info( "No artifact parameter specified, using '" + project.getId() + "' as project." );
275 }
276 }
277
278
279
280
281
282
283 private Artifact getArtifact( String artifactString )
284 throws MojoExecutionException
285 {
286 if ( StringUtils.isEmpty( artifactString ) )
287 {
288 throw new IllegalArgumentException( "artifact parameter could not be empty" );
289 }
290
291 String groupId = null;
292 String artifactId = null;
293 String version = null;
294 String classifier = null;
295
296 String[] artifactParts = artifactString.split( ":" );
297
298 switch ( artifactParts.length )
299 {
300 case ( 2 ):
301 groupId = artifactParts[0];
302 artifactId = artifactParts[1];
303 version = Artifact.LATEST_VERSION;
304 break;
305 case ( 3 ):
306 groupId = artifactParts[0];
307 artifactId = artifactParts[1];
308 version = artifactParts[2];
309 break;
310 case ( 4 ):
311 groupId = artifactParts[0];
312 artifactId = artifactParts[1];
313 version = artifactParts[2];
314 classifier = artifactParts[3];
315 break;
316 default:
317 throw new MojoExecutionException( "The artifact parameter '" + artifactString
318 + "' should be conform to: " + "'groupId:artifactId[:version][:classifier]'." );
319 }
320
321 if ( StringUtils.isNotEmpty( classifier ) )
322 {
323 return artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, "jar", classifier );
324 }
325
326 return artifactFactory.createArtifact( groupId, artifactId, version, Artifact.SCOPE_COMPILE, "jar" );
327 }
328
329
330
331
332
333
334
335 private MavenProject getMavenProject( Artifact artifactObj )
336 throws MojoExecutionException, ProjectBuildingException
337 {
338 if ( Artifact.SCOPE_SYSTEM.equals( artifactObj.getScope() ) )
339 {
340 throw new MojoExecutionException( "System artifact is not be handled." );
341 }
342
343 Artifact copyArtifact = ArtifactUtils.copyArtifact( artifactObj );
344 if ( !"pom".equals( copyArtifact.getType() ) )
345 {
346 copyArtifact =
347 artifactFactory.createProjectArtifact( copyArtifact.getGroupId(), copyArtifact.getArtifactId(),
348 copyArtifact.getVersion(), copyArtifact.getScope() );
349 }
350
351 return mavenProjectBuilder.buildFromRepository( copyArtifact, remoteRepositories, localRepository );
352 }
353
354
355
356
357
358
359
360 private PluginParameterExpressionEvaluator getEvaluator()
361 throws MojoExecutionException, MojoFailureException
362 {
363 if ( evaluator == null )
364 {
365 MojoDescriptor mojoDescriptor =
366 HelpUtil.getMojoDescriptor( "help:evaluate", session, project, "help:evaluate", true, false );
367 MojoExecution mojoExecution = new MojoExecution( mojoDescriptor );
368 evaluator =
369 new PluginParameterExpressionEvaluator( session, mojoExecution, pathTranslator,
370 loggerRetriever.getLogger(), project,
371 session.getExecutionProperties() );
372 }
373
374 return evaluator;
375 }
376
377
378
379
380
381
382 private void handleResponse( String expression )
383 throws MojoExecutionException, MojoFailureException
384 {
385 StringBuffer response = new StringBuffer();
386
387 Object obj;
388 try
389 {
390 obj = getEvaluator().evaluate( expression );
391 }
392 catch ( ExpressionEvaluationException e )
393 {
394 throw new MojoExecutionException( "Error when evaluating the Maven expression", e );
395 }
396
397 if ( obj != null && expression.equals( obj.toString() ) )
398 {
399 getLog().warn( "The Maven expression was invalid. Please use a valid expression." );
400 return;
401 }
402
403
404 if ( obj == null )
405 {
406 response.append( "null object or invalid expression" );
407 }
408
409 else if ( obj instanceof String )
410 {
411 response.append( obj.toString() );
412 }
413 else if ( obj instanceof Boolean )
414 {
415 response.append( obj.toString() );
416 }
417 else if ( obj instanceof Byte )
418 {
419 response.append( obj.toString() );
420 }
421 else if ( obj instanceof Character )
422 {
423 response.append( obj.toString() );
424 }
425 else if ( obj instanceof Double )
426 {
427 response.append( obj.toString() );
428 }
429 else if ( obj instanceof Float )
430 {
431 response.append( obj.toString() );
432 }
433 else if ( obj instanceof Integer )
434 {
435 response.append( obj.toString() );
436 }
437 else if ( obj instanceof Long )
438 {
439 response.append( obj.toString() );
440 }
441 else if ( obj instanceof Short )
442 {
443 response.append( obj.toString() );
444 }
445
446 else if ( obj instanceof File )
447 {
448 File f = (File) obj;
449 response.append( f.getAbsolutePath() );
450 }
451
452 else if ( obj instanceof MavenProject )
453 {
454 MavenProject projectAsked = (MavenProject) obj;
455 StringWriter sWriter = new StringWriter();
456 MavenXpp3Writer pomWriter = new MavenXpp3Writer();
457 try
458 {
459 pomWriter.write( sWriter, projectAsked.getModel() );
460 }
461 catch ( IOException e )
462 {
463 throw new MojoExecutionException( "Error when writing pom", e );
464 }
465
466 response.append( sWriter.toString() );
467 }
468
469 else if ( obj instanceof Settings )
470 {
471 Settings settingsAsked = (Settings) obj;
472 StringWriter sWriter = new StringWriter();
473 SettingsXpp3Writer settingsWriter = new SettingsXpp3Writer();
474 try
475 {
476 settingsWriter.write( sWriter, settingsAsked );
477 }
478 catch ( IOException e )
479 {
480 throw new MojoExecutionException( "Error when writing settings", e );
481 }
482
483 response.append( sWriter.toString() );
484 }
485 else
486 {
487
488 response.append( toXML( expression, obj ) );
489 }
490
491 getLog().info( "\n" + response.toString() );
492 }
493
494
495
496
497
498
499 private String toXML( String expression, Object obj )
500 {
501 XStream currentXStream = getXStream();
502
503
504 if ( obj instanceof List )
505 {
506 List list = (List) obj;
507 if ( list.size() > 0 )
508 {
509 Object elt = list.iterator().next();
510
511 String name = StringUtils.lowercaseFirstLetter( ClassUtils.getShortClassName( elt.getClass() ) );
512 currentXStream.alias( pluralize( name ), List.class );
513 }
514 else
515 {
516
517 if ( expression.indexOf( "." ) != -1 )
518 {
519 String name = expression.substring( expression.indexOf( "." ) + 1, expression.indexOf( "}" ) );
520 currentXStream.alias( name, List.class );
521 }
522 }
523 }
524
525 return currentXStream.toXML( obj );
526 }
527
528
529
530
531 private XStream getXStream()
532 {
533 if ( xstream == null )
534 {
535 xstream = new XStream();
536 addAlias( xstream );
537
538
539 xstream.registerConverter( new PropertiesConverter()
540 {
541
542 public boolean canConvert( Class type )
543 {
544 return Properties.class == type;
545 }
546
547
548 public void marshal( Object source, HierarchicalStreamWriter writer, MarshallingContext context )
549 {
550 Properties properties = (Properties) source;
551 Map map = new TreeMap( properties );
552 for ( Iterator iterator = map.entrySet().iterator(); iterator.hasNext(); )
553 {
554 Map.Entry entry = (Map.Entry) iterator.next();
555
556 writer.startNode( entry.getKey().toString() );
557 writer.setValue( entry.getValue().toString() );
558 writer.endNode();
559 }
560 }
561 } );
562 }
563
564 return xstream;
565 }
566
567
568
569
570 private void addAlias( XStream xstreamObject )
571 {
572 try
573 {
574 addAlias( xstreamObject, getMavenModelJarFile(), "org.apache.maven.model" );
575 addAlias( xstreamObject, getMavenSettingsJarFile(), "org.apache.maven.settings" );
576 }
577 catch ( MojoExecutionException e )
578 {
579 if ( getLog().isDebugEnabled() )
580 {
581 getLog().debug( "MojoExecutionException: " + e.getMessage(), e );
582 }
583 }
584 catch ( ArtifactResolutionException e )
585 {
586 if ( getLog().isDebugEnabled() )
587 {
588 getLog().debug( "ArtifactResolutionException: " + e.getMessage(), e );
589 }
590 }
591 catch ( ArtifactNotFoundException e )
592 {
593 if ( getLog().isDebugEnabled() )
594 {
595 getLog().debug( "ArtifactNotFoundException: " + e.getMessage(), e );
596 }
597 }
598 catch ( ProjectBuildingException e )
599 {
600 if ( getLog().isDebugEnabled() )
601 {
602 getLog().debug( "ProjectBuildingException: " + e.getMessage(), e );
603 }
604 }
605
606
607 }
608
609
610
611
612
613
614 private void addAlias( XStream xstreamObject, File jarFile, String packageFilter )
615 {
616 JarInputStream jarStream = null;
617 try
618 {
619 jarStream = new JarInputStream( new FileInputStream( jarFile ) );
620 JarEntry jarEntry = jarStream.getNextJarEntry();
621 while ( jarEntry != null )
622 {
623 if ( jarEntry == null )
624 {
625 break;
626 }
627
628 if ( jarEntry.getName().toLowerCase( Locale.ENGLISH ).endsWith( ".class" ) )
629 {
630 String name = jarEntry.getName().substring( 0, jarEntry.getName().indexOf( "." ) );
631 name = name.replaceAll( "/", "\\." );
632
633 if ( name.indexOf( packageFilter ) != -1 )
634 {
635 try
636 {
637 Class clazz = ClassUtils.getClass( name );
638 String alias = StringUtils.lowercaseFirstLetter( ClassUtils.getShortClassName( clazz ) );
639 xstreamObject.alias( alias, clazz );
640 if ( !clazz.equals( Model.class ) )
641 {
642 xstreamObject.omitField( clazz, "modelEncoding" );
643 }
644 }
645 catch ( ClassNotFoundException e )
646 {
647 e.printStackTrace();
648 }
649 }
650 }
651
652 jarStream.closeEntry();
653 jarEntry = jarStream.getNextJarEntry();
654 }
655 }
656 catch ( IOException e )
657 {
658 if ( getLog().isDebugEnabled() )
659 {
660 getLog().debug( "IOException: " + e.getMessage(), e );
661 }
662 }
663 finally
664 {
665 IOUtil.close( jarStream );
666 }
667 }
668
669
670
671
672
673
674
675
676 private File getMavenModelJarFile()
677 throws MojoExecutionException, ProjectBuildingException, ArtifactResolutionException,
678 ArtifactNotFoundException
679 {
680 return getArtifactFile( true );
681 }
682
683
684
685
686
687
688
689
690 private File getMavenSettingsJarFile()
691 throws MojoExecutionException, ProjectBuildingException, ArtifactResolutionException,
692 ArtifactNotFoundException
693 {
694 return getArtifactFile( false );
695 }
696
697
698
699
700
701
702
703
704
705
706
707
708 private File getArtifactFile( boolean isPom )
709 throws MojoExecutionException, ProjectBuildingException, ArtifactResolutionException,
710 ArtifactNotFoundException
711 {
712 for ( Iterator it = getHelpPluginPom().getDependencies().iterator(); it.hasNext(); )
713 {
714 Dependency depependency = (Dependency) it.next();
715
716 if ( !( depependency.getGroupId().equals( "org.apache.maven" ) ) )
717 {
718 continue;
719 }
720
721 if ( isPom )
722 {
723 if ( !( depependency.getArtifactId().equals( "maven-model" ) ) )
724 {
725 continue;
726 }
727 }
728 else
729 {
730 if ( !( depependency.getArtifactId().equals( "maven-settings" ) ) )
731 {
732 continue;
733 }
734 }
735
736 Artifact mavenArtifact =
737 getArtifact( depependency.getGroupId() + ":" + depependency.getArtifactId() + ":"
738 + depependency.getVersion() );
739 resolver.resolveAlways( mavenArtifact, remoteRepositories, localRepository );
740
741 return mavenArtifact.getFile();
742 }
743
744 throw new MojoExecutionException( "Unable to find the 'org.apache.maven:"
745 + ( isPom ? "maven-model" : "maven-settings" ) + "' artifact" );
746 }
747
748
749
750
751
752
753 private MavenProject getHelpPluginPom()
754 throws MojoExecutionException, ProjectBuildingException
755 {
756 String resource = "META-INF/maven/org.apache.maven.plugins/maven-help-plugin/pom.properties";
757
758 InputStream resourceAsStream = EvaluateMojo.class.getClassLoader().getResourceAsStream( resource );
759 Artifact helpPluginArtifact = null;
760 if ( resourceAsStream != null )
761 {
762 Properties properties = new Properties();
763 try
764 {
765 properties.load( resourceAsStream );
766 }
767 catch ( IOException e )
768 {
769 if ( getLog().isDebugEnabled() )
770 {
771 getLog().debug( "IOException: " + e.getMessage(), e );
772 }
773 }
774
775 String artifactString =
776 properties.getProperty( "groupId", "unknown" ) + ":"
777 + properties.getProperty( "artifactId", "unknown" ) + ":"
778 + properties.getProperty( "version", "unknown" );
779
780 helpPluginArtifact = getArtifact( artifactString );
781 }
782
783 if ( helpPluginArtifact == null )
784 {
785 throw new MojoExecutionException( "The help plugin artifact was not found." );
786 }
787
788 return getMavenProject( helpPluginArtifact );
789 }
790
791
792
793
794
795 private static String pluralize( String name )
796 {
797 if ( StringUtils.isEmpty( name ) )
798 {
799 throw new IllegalArgumentException( "name is required" );
800 }
801
802 if ( name.endsWith( "y" ) )
803 {
804 return name.substring( 0, name.length() - 1 ) + "ies";
805 }
806 else if ( name.endsWith( "s" ) )
807 {
808 return name;
809 }
810 else
811 {
812 return name + "s";
813 }
814 }
815 }