1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 package org.codehaus.mojo.jaxws;
37
38 import java.io.File;
39 import java.io.FileOutputStream;
40 import java.io.IOException;
41 import java.net.URI;
42 import java.net.URISyntaxException;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Properties;
50 import java.util.Set;
51 import java.util.stream.Collectors;
52
53 import org.apache.maven.artifact.Artifact;
54 import org.apache.maven.artifact.versioning.ArtifactVersion;
55 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
56 import org.apache.maven.execution.MavenSession;
57 import org.apache.maven.plugin.AbstractMojo;
58 import org.apache.maven.plugin.MojoExecutionException;
59 import org.apache.maven.plugin.MojoFailureException;
60 import org.apache.maven.plugin.descriptor.PluginDescriptor;
61 import org.apache.maven.plugins.annotations.Component;
62 import org.apache.maven.plugins.annotations.Parameter;
63 import org.apache.maven.project.MavenProject;
64 import org.apache.maven.toolchain.Toolchain;
65 import org.apache.maven.toolchain.ToolchainManager;
66 import org.codehaus.plexus.util.Os;
67 import org.codehaus.plexus.util.cli.CommandLineException;
68 import org.codehaus.plexus.util.cli.CommandLineUtils;
69 import org.codehaus.plexus.util.cli.Commandline;
70 import org.codehaus.plexus.util.cli.StreamConsumer;
71
72
73
74
75
76 abstract class AbstractJaxwsMojo
77 extends AbstractMojo
78 {
79
80
81
82
83 @Parameter( defaultValue = "${project}", readonly = true, required = true )
84 protected MavenProject project;
85
86
87
88
89 @Parameter( defaultValue = "false" )
90 protected boolean verbose;
91
92
93
94
95 @Parameter( defaultValue = "true" )
96 protected boolean keep;
97
98
99
100
101 @Parameter( defaultValue = "false" )
102 private boolean extension;
103
104
105
106
107 @Parameter( defaultValue = "${project.build.sourceEncoding}" )
108 protected String encoding;
109
110
111
112
113
114
115
116 @Parameter
117 private List<String> args;
118
119
120
121
122
123
124
125 @Parameter
126 private List<String> vmArgs;
127
128
129
130
131
132
133
134
135 @Parameter
136 private File executable;
137
138
139
140
141
142
143
144 @Parameter( defaultValue = "${plugin}", readonly = true )
145 protected PluginDescriptor pluginDescriptor;
146
147
148
149
150 @Component
151 private ToolchainManager toolchainManager;
152
153
154
155
156
157
158
159
160 @Parameter( defaultValue = "false" )
161 private boolean useJdkToolchainExecutable;
162
163
164
165
166 @Parameter( defaultValue = "${session}", readonly = true, required = true )
167 protected MavenSession session;
168
169
170 private static final List<String> METRO_22 = new ArrayList<>();
171
172
173 private static final List<String> METRO_221 = new ArrayList<>();
174
175
176 private static final List<String> METRO_23 = new ArrayList<>();
177
178 static
179 {
180 METRO_22.add( "-encoding" );
181 METRO_22.add( "-clientjar" );
182 METRO_22.add( "-generateJWS" );
183 METRO_22.add( "-implDestDir" );
184 METRO_22.add( "-implServiceName" );
185 METRO_22.add( "-implPortName" );
186
187 METRO_221.addAll( METRO_22 );
188 METRO_221.add( "-XdisableAuthenticator" );
189
190 METRO_23.addAll( METRO_221 );
191 METRO_23.add( "-x" );
192 }
193
194
195
196
197
198 protected abstract String getMain();
199
200
201
202
203
204 protected abstract String getToolName();
205
206
207
208
209
210 protected abstract File getDestDir();
211
212 protected abstract File getSourceDestDir();
213
214 protected void addSourceRoot( String sourceDir )
215 {
216 if ( !project.getCompileSourceRoots().contains( sourceDir ) )
217 {
218 getLog().debug( "adding src root: " + sourceDir );
219 project.addCompileSourceRoot( sourceDir );
220 }
221 else
222 {
223 getLog().debug( "existing src root: " + sourceDir );
224 }
225 }
226
227 protected abstract File getDefaultSrcOut();
228
229
230
231
232
233
234 protected abstract boolean isXnocompile();
235
236 protected String getExtraClasspath()
237 {
238 return null;
239 }
240
241 protected boolean isExtensionOn()
242 {
243 return extension;
244 }
245
246 protected List<String> getCommonArgs()
247 throws MojoExecutionException
248 {
249 List<String> commonArgs = new ArrayList<>();
250
251 if ( !isDefaultSrc( getSourceDestDir() ) || keep )
252 {
253 commonArgs.add( "-keep" );
254 commonArgs.add( "-s" );
255 commonArgs.add( "'" + getSourceDestDir().getAbsolutePath() + "'" );
256 if ( !getSourceDestDir().mkdirs() && !getSourceDestDir().exists() )
257 {
258 getLog().warn( "Cannot create directory: " + getSourceDestDir().getAbsolutePath() );
259 }
260 addSourceRoot( getSourceDestDir().getAbsolutePath() );
261 }
262
263 File destDir = getDestDir();
264 if ( !destDir.mkdirs() && !destDir.exists() )
265 {
266 getLog().warn( "Cannot create directory: " + destDir.getAbsolutePath() );
267 }
268 commonArgs.add( "-d" );
269 commonArgs.add( "'" + destDir.getAbsolutePath() + "'" );
270
271 if ( verbose )
272 {
273 commonArgs.add( "-verbose" );
274 }
275
276 if ( isArgSupported( "-encoding" ) )
277 {
278 if ( encoding != null )
279 {
280 commonArgs.add( "-encoding" );
281 commonArgs.add( encoding );
282 }
283 else
284 {
285 getLog().warn( "Using platform encoding (" + System.getProperty( "file.encoding" )
286 + "), build is platform dependent!" );
287 }
288 }
289
290 if ( isExtensionOn() )
291 {
292 commonArgs.add( "-extension" );
293 }
294
295 if ( isXnocompile() )
296 {
297 commonArgs.add( "-Xnocompile" );
298 }
299
300
301 if ( args != null )
302 {
303 for ( String arg : args )
304 {
305 commonArgs.add( arg );
306 }
307 }
308
309 return commonArgs;
310 }
311
312 protected boolean isArgSupported( String arg )
313 throws MojoExecutionException
314 {
315
316 List<String> supportedArgs = METRO_23;
317
318
319
320 Artifact a = pluginDescriptor.getArtifactMap().get( "org.glassfish.metro:webservices-tools" );
321 String v = null;
322 if ( a != null )
323 {
324 ArtifactVersion av = getSelectedVersion( a );
325 v = av.toString();
326 if ( av.getMajorVersion() == 2 && av.getMinorVersion() == 2 )
327 {
328 supportedArgs = av.getIncrementalVersion() == 0 ? METRO_22 : METRO_221;
329 }
330 }
331 else
332 {
333
334 a = pluginDescriptor.getArtifactMap().get( "com.sun.xml.ws:jaxws-tools" );
335 ArtifactVersion av = getSelectedVersion( a );
336 v = av.toString();
337 if ( av.getMajorVersion() == 2 && av.getMinorVersion() == 2 )
338 {
339 if ( av.getIncrementalVersion() == 6 )
340 {
341 supportedArgs = METRO_22;
342 }
343 else if ( av.getIncrementalVersion() == 7 )
344 {
345 supportedArgs = METRO_221;
346 }
347 }
348 }
349
350 boolean isSupported = supportedArgs.contains( arg );
351 if ( !isSupported )
352 {
353 getLog().warn( "'" + arg + "' is not supported by " + a.getArtifactId() + ":" + v );
354 }
355 return isSupported;
356 }
357
358 private static ArtifactVersion getSelectedVersion( Artifact artifact )
359 throws MojoExecutionException
360 {
361 try
362 {
363 return artifact.getSelectedVersion();
364 }
365 catch ( OverConstrainedVersionException ex )
366 {
367 throw new MojoExecutionException( ex.getMessage(), ex );
368 }
369 }
370
371 private boolean isDefaultSrc( File srcout )
372 {
373 return srcout.equals( getDefaultSrcOut() );
374 }
375
376 @Override
377 public final void execute()
378 throws MojoExecutionException, MojoFailureException
379 {
380 if ( executable == null && getJdkToolchain() != null && useJdkToolchainExecutable )
381 {
382
383 executable = new File( getJdkToolchain().findTool( getToolName() ) );
384 }
385
386 executeJaxws();
387 }
388
389 public abstract void executeJaxws()
390 throws MojoExecutionException, MojoFailureException;
391
392 protected void exec( List<String> arguments )
393 throws MojoExecutionException
394 {
395 String launched = "";
396 Commandline cmd = new Commandline();
397
398 if ( executable != null )
399 {
400
401 launched = executable.getName();
402 if ( executable.isFile() && executable.canExecute() )
403 {
404 cmd.setExecutable( executable.getAbsolutePath() );
405 if ( getExtraClasspath() != null )
406 {
407 cmd.createArg().setLine( "-cp" );
408 cmd.createArg().setValue( getExtraClasspath() );
409 }
410 }
411 else
412 {
413 throw new MojoExecutionException( "Cannot execute: " + executable.getAbsolutePath() );
414 }
415 }
416 else
417 {
418
419 launched = getMain();
420
421 if ( getJdkToolchain() == null )
422 {
423
424 cmd.setExecutable( new File( new File( System.getProperty( "java.home" ), "bin" ),
425 getJavaExec() ).getAbsolutePath() );
426 }
427 else
428 {
429
430 cmd.setExecutable( getJdkToolchain().findTool( "java" ) );
431 }
432
433
434 if ( vmArgs != null )
435 {
436 for ( String arg : vmArgs )
437 {
438 cmd.createArg().setLine( arg );
439 }
440 }
441 InvokerCP classpath = getInvokerCP();
442 if ( !isModular() ) {
443 cmd.createArg().setValue( "-Xbootclasspath/p:" + classpath.ecp );
444 }
445 cmd.createArg().setValue( "-cp" );
446 cmd.createArg().setValue( classpath.invokerPath );
447 cmd.createArg().setLine( Invoker.class.getCanonicalName() );
448 cmd.createArg().setLine( getMain() );
449 String extraCp = getExtraClasspath();
450 String cp = ( ( extraCp != null ) ? ( extraCp + File.pathSeparator ) : "" ) + classpath.cp;
451 try
452 {
453 File pathFile = createPathFile( cp );
454 cmd.createArg().setLine( "-pathfile " + "'" + pathFile.getAbsolutePath() + "'" );
455 }
456 catch ( IOException ioe )
457 {
458
459 cmd.createArg().setValue( "-cp" );
460 cmd.createArg().setValue( cp );
461 }
462 }
463
464 cmd.setWorkingDirectory( project.getBasedir() );
465 for ( String arg : arguments )
466 {
467 cmd.createArg().setLine( arg );
468 }
469
470 try
471 {
472 String fullCommand = cmd.toString();
473 if ( isWindows() && 8191 <= fullCommand.length() )
474 {
475 getLog().warn( "Length of Windows command line is limited to 8191 characters, but current command has "
476 + fullCommand.length() + " characters:" );
477 getLog().warn( fullCommand );
478 }
479 else
480 {
481 getLog().debug( fullCommand );
482 }
483
484
485
486
487
488
489
490
491 StreamConsumer sc = new StreamConsumer() {
492 public void consumeLine( String line )
493 {
494 System.out.println( line );
495 }
496 };
497
498 if ( CommandLineUtils.executeCommandLine( cmd, sc, sc ) != 0 )
499 {
500 throw new MojoExecutionException( "Invocation of " + launched + " failed - check output" );
501 }
502 }
503 catch ( CommandLineException t )
504 {
505 throw new MojoExecutionException( t.getMessage(), t );
506 }
507 }
508
509 private boolean isModular() {
510 try
511 {
512 Class<?> moduleClass = Class.forName( "java.lang.Module" );
513 return moduleClass != null;
514 }
515 catch ( ClassNotFoundException e )
516 {
517 return false;
518 }
519 }
520
521 protected void maybeUnsupportedOption( String option, String value, List<String> arguments )
522 {
523 if ( executable == null )
524 {
525 arguments.add( option );
526 if ( value != null )
527 {
528 arguments.add( value );
529 }
530 }
531 else
532 {
533 getLog().warn( option + " may not supported on older JDKs.\n"
534 + "Use <args> to bypass this warning if you really want to use it." );
535 }
536 }
537
538
539
540
541
542
543 private InvokerCP getInvokerCP()
544 {
545 Set<Artifact> endorsedArtifacts = new HashSet<>();
546 Map<String, Artifact> artifactsMap = new HashMap<>();
547 for ( Artifact a : pluginDescriptor.getArtifacts() )
548 {
549 addArtifactToCp( a, artifactsMap, endorsedArtifacts );
550 }
551
552 StringBuilder cp = new StringBuilder( getCPasString( artifactsMap.values() ) );
553 StringBuilder ecp = new StringBuilder( getCPasString( endorsedArtifacts ) );
554
555 String invokerPath = null;
556 try
557 {
558 invokerPath = Invoker.class.getProtectionDomain().getCodeSource().getLocation().toExternalForm();
559 invokerPath = new URI( invokerPath.substring( 5 ) ).getPath();
560 }
561 catch ( URISyntaxException ex )
562 {
563 throw new RuntimeException( ex );
564 }
565
566
567 if ( cp.length() > 0 ) {
568 cp.append( File.pathSeparator );
569 }
570 cp.append( invokerPath );
571
572
573 String javaHome = getJavaHome();
574 File toolsJar = new File( javaHome, "../lib/tools.jar" );
575 if ( !toolsJar.exists() )
576 {
577 toolsJar = new File( javaHome, "lib/tools.jar" );
578 }
579
580 if ( toolsJar.exists() ) {
581 if ( cp.length() > 0 ) {
582 cp.append( File.pathSeparator );
583 }
584 cp.append( toolsJar.getAbsolutePath() );
585 }
586
587 if ( getLog().isDebugEnabled() )
588 {
589 getLog().debug( "getInvokerCP():\n"
590 + " endorsed: " + toString( endorsedArtifacts ) + "\n"
591 + " classpath: " + toString( artifactsMap.values() ) + "\n"
592 + " ecp: " + ecp + "\n"
593 + " cp: " + cp + "\n"
594 + " invokerPath: " + invokerPath );
595 }
596
597 return new InvokerCP( ecp.toString(), cp.toString(), invokerPath );
598 }
599
600 private static class InvokerCP
601 {
602 public final String ecp;
603
604 public final String cp;
605
606 public final String invokerPath;
607
608 public InvokerCP( String ecp, String cp, String invokerPath )
609 {
610 this.ecp = ecp;
611 this.cp = cp;
612 this.invokerPath = invokerPath;
613 }
614 }
615
616 private String getJavaExec()
617 {
618 return isWindows() ? "java.exe" : "java";
619 }
620
621 private String getJavaHome()
622 {
623
624 String javaHome = System.getProperty( "java.home" );
625 if ( getJdkToolchain() != null )
626 {
627
628 File javaExecutable = new File( getJdkToolchain().findTool( "java" ) );
629 javaHome = javaExecutable.getParentFile().getParent();
630 }
631 return javaHome;
632 }
633
634 private File createPathFile( String cp )
635 throws IOException
636 {
637 File f = File.createTempFile( "jax-ws-mvn-plugin-cp", ".txt" );
638 if ( f.exists() && f.isFile() && !f.delete() )
639 {
640
641 getLog().warn( "cannot remove obsolete classpath setting file: " + f.getAbsolutePath() );
642 }
643 Properties p = new Properties();
644 p.put( "cp", cp.replace( File.separatorChar, '/' ) );
645 getLog().debug( "stored classpath: " + cp.replace( File.separatorChar, '/' ) );
646 try (FileOutputStream fos = new FileOutputStream( f )) {
647 p.store( fos, null );
648 }
649 catch ( IOException ex )
650 {
651 getLog().error( ex );
652 }
653 return f;
654 }
655
656 private boolean isWindows()
657 {
658 return Os.isFamily( Os.FAMILY_WINDOWS );
659 }
660
661 protected String getCPasString( Collection<Artifact> artifacts )
662 {
663 return artifacts.stream().map( a -> a.getFile().getAbsolutePath() ).collect( Collectors.joining( File.pathSeparator ) );
664 }
665
666 private String toString(Collection<Artifact> artifacts) {
667 return artifacts
668 .stream().map( a -> String.join( ":", a.getGroupId(), a.getArtifactId(), a.getVersion() ) )
669 .collect( Collectors.joining( " " ) );
670 }
671
672
673
674
675
676
677
678
679
680
681 private void addArtifactToCp( Artifact a, Map<String, Artifact> artifactsMap, Set<Artifact> endorsedArtifacts )
682 {
683 if ( !isModular() && isEndorsedArtifact( a ) )
684 {
685 endorsedArtifacts.add( a );
686 }
687 else if ( "compile".equals( a.getScope() ) || "runtime".equals( a.getScope() ) )
688 {
689 artifactsMap.put( a.getGroupId() + ":" + a.getArtifactId(), a );
690 }
691 }
692
693 protected void addVmArg( String vmArg )
694 {
695 if ( vmArgs == null )
696 {
697 vmArgs = new ArrayList<>();
698 }
699 vmArgs.add( vmArg );
700 }
701
702 private boolean isEndorsedArtifact( Artifact a )
703 {
704 return "jaxws-api".equals( a.getArtifactId() )
705 || "jaxb-api".equals( a.getArtifactId() )
706 || "saaj-api".equals( a.getArtifactId() )
707 || "jsr181-api".equals( a.getArtifactId() )
708 || "javax.annotation".equals( a.getArtifactId() )
709 || "javax.annotation-api".equals( a.getArtifactId() )
710 || "webservices-api".equals( a.getArtifactId() )
711 || a.getArtifactId().startsWith( "javax.xml.ws" )
712 || a.getArtifactId().startsWith( "javax.xml.bind" );
713 }
714
715 private Toolchain getJdkToolchain()
716 {
717 Toolchain tc = null;
718 if ( toolchainManager != null )
719 {
720 tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
721 }
722 return tc;
723 }
724 }