1   /*
2    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3    *
4    * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
5    *
6    * Oracle licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   *
18   * 
19   * This file incorporates work covered by the following copyright and
20   * permission notice:
21   *
22   * Copyright 2006 Guillaume Nodet
23   *
24   * Licensed under the Apache License, Version 2.0 (the "License");
25   * you may not use this file except in compliance with the License.
26   * You may obtain a copy of the License at
27   *
28   *      http://www.apache.org/licenses/LICENSE-2.0
29   *
30   * Unless required by applicable law or agreed to in writing, software
31   * distributed under the License is distributed on an "AS IS" BASIS,
32   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33   * See the License for the specific language governing permissions and
34   * limitations under the License.
35   */
36  
37  package org.codehaus.mojo.jaxws;
38  
39  import java.io.File;
40  import java.io.IOException;
41  import java.net.URL;
42  import java.net.URLClassLoader;
43  import java.util.ArrayList;
44  import java.util.HashSet;
45  import java.util.Set;
46  
47  import javax.jws.WebService;
48  
49  import org.apache.maven.model.Resource;
50  import org.apache.maven.plugin.MojoExecutionException;
51  import org.apache.maven.plugin.MojoFailureException;
52  import org.apache.maven.plugins.annotations.Parameter;
53  import org.codehaus.plexus.util.FileUtils;
54  
55  /**
56   * 
57   *
58   * @author gnodet (gnodet@apache.org)
59   * @author dantran (dantran@apache.org)
60   */
61  abstract class AbstractWsGenMojo
62      extends AbstractJaxwsMojo
63  {
64  
65      /**
66       * Specify that a WSDL file should be generated in <code>${resourceDestDir}</code>.
67       */
68      @Parameter( defaultValue = "false" )
69      protected boolean genWsdl;
70  
71      /**
72       * Service endpoint implementation class name.
73       */
74      @Parameter
75      private String sei;
76  
77      /**
78       * Used in conjunction with <code>genWsdl<code> to specify the protocol to use in the
79       * <code>wsdl:binding</code>. Valid values are "<code>soap1.1</code>" or "<code>Xsoap1.2</code>",
80       * default is "<code>soap1.1</code>". "<code>Xsoap1.2</code>" is not standard
81       * and can only be used in conjunction with the <code>extension</code> option.
82       */
83      @Parameter
84      private String protocol;
85  
86      /**
87       * Specify the Service name to use in the generated WSDL.
88       * Used in conjunction with the <code>genWsdl</code> option.
89       */
90      @Parameter
91      private String servicename;
92  
93      /**
94       * Specify the Port name to use in the generated WSDL.
95       * Used in conjunction with the <code>genWsdl</code> option.
96       */
97      @Parameter
98      private String portname;
99  
100     /**
101      * Inline schemas in the generated WSDL.
102      * Used in conjunction with the <code>genWsdl</code> option.
103      */
104     @Parameter( defaultValue = "false" )
105     private boolean inlineSchemas;
106 
107     /**
108      * Turn off compilation after code generation and let generated sources be
109      * compiled by maven during compilation phase; keep is turned on with this option.
110      */
111     @Parameter( defaultValue = "false" )
112     private boolean xnocompile;
113 
114     /**
115      */
116     @Parameter( defaultValue = "false" )
117     private boolean xdonotoverwrite;
118 
119     /**
120      * Metadata file for wsgen. See
121      * <a href="https://jax-ws.java.net/2.2.8/docs/ch03.html#users-guide-external-metadata">the JAX-WS Guide</a>
122      * for the description of this feature.
123      * Unmatched files will be ignored.
124      *
125      * @since 2.3
126      * @see <a href="https://jax-ws.java.net/2.2.8/docs/ch03.html#users-guide-external-metadata">External Web Service Metadata</a>
127      */
128     @Parameter
129     private File metadata;
130 
131     protected abstract File getResourceDestDir();
132 
133     protected abstract File getClassesDir();
134 
135     @Override
136     public void executeJaxws()
137         throws MojoExecutionException, MojoFailureException
138     {
139         Set<String> seis = new HashSet<>();
140         if ( sei != null )
141         {
142             seis.add( sei );
143         }
144         else
145         {
146             // find all SEIs within current classes
147             seis.addAll( getSEIs( getClassesDir() ) );
148         }
149         if ( seis.isEmpty() )
150         {
151             throw new MojoFailureException( "No @javax.jws.WebService found." );
152         }
153         for ( String aSei : seis )
154         {
155             processSei( aSei );
156         }
157     }
158 
159     protected void processSei( String aSei )
160         throws MojoExecutionException
161     {
162         getLog().info( "Processing: " + aSei );
163         ArrayList<String> args = getWsGenArgs( aSei );
164         getLog().info( "jaxws:wsgen args: " + args );
165         exec( args );
166         if ( metadata != null )
167         {
168             try
169             {
170                 FileUtils.copyFileToDirectory( metadata, getClassesDir() );
171             }
172             catch ( IOException ioe )
173             {
174                 throw new MojoExecutionException( ioe.getMessage(), ioe );
175             }
176         }
177     }
178 
179     @Override
180     protected String getMain()
181     {
182         return "com.sun.tools.ws.wscompile.WsgenTool";
183     }
184 
185     @Override
186     protected String getToolName()
187     {
188         return "wsgen";
189     }
190 
191     @Override
192     protected String getExtraClasspath()
193     {
194         return String.join( File.pathSeparator,
195                 getClassesDir().getAbsolutePath(),
196                 getCPasString( project.getArtifacts() ) );
197     }
198 
199     @Override
200     protected boolean isXnocompile()
201     {
202         return xnocompile;
203     }
204 
205     /**
206      * Returns wsgen's command arguments as a list
207      */
208     private ArrayList<String> getWsGenArgs( String aSei )
209         throws MojoExecutionException
210     {
211         ArrayList<String> args = new ArrayList<>();
212         args.addAll( getCommonArgs() );
213 
214         if ( this.genWsdl )
215         {
216             if ( this.protocol != null )
217             {
218                 args.add( "-wsdl:" + this.protocol );
219             }
220             else
221             {
222                 args.add( "-wsdl" );
223             }
224 
225             if ( inlineSchemas )
226             {
227                 maybeUnsupportedOption( "-inlineSchemas", null, args );
228             }
229 
230             if ( servicename != null )
231             {
232                 args.add( "-servicename" );
233                 args.add( servicename );
234             }
235 
236             if ( portname != null )
237             {
238                 args.add( "-portname" );
239                 args.add( portname );
240             }
241 
242             File resourceDir = getResourceDestDir();
243             if ( !resourceDir.mkdirs() && !resourceDir.exists() )
244             {
245                 getLog().warn( "Cannot create directory: " + resourceDir.getAbsolutePath() );
246             }
247             args.add( "-r" );
248             args.add( "'" + resourceDir.getAbsolutePath() + "'" );
249             if ( !"war".equals( project.getPackaging() ) )
250             {
251                 Resource r = new Resource();
252                 r.setDirectory( getRelativePath( project.getBasedir(), getResourceDestDir() ) );
253                 project.addResource( r );
254             }
255         }
256 
257         if ( xdonotoverwrite )
258         {
259             args.add( "-Xdonotoverwrite" );
260         }
261 
262         if ( metadata != null && isArgSupported( "-x" ) )
263         {
264             maybeUnsupportedOption( "-x", "'" + metadata.getAbsolutePath() + "'", args );
265         }
266 
267         args.add( aSei );
268 
269         return args;
270     }
271 
272     private String getRelativePath( File root, File f )
273     {
274         return root.toURI().relativize( f.toURI() ).getPath();
275     }
276 
277     private Set<String> getSEIs( File directory )
278         throws MojoExecutionException
279     {
280         Set<String> seis = new HashSet<>();
281         if ( !directory.exists() || directory.isFile() )
282         {
283             return seis;
284         }
285         try ( URLClassLoader cl = new URLClassLoader( new URL[] { directory.toURI().toURL() }, getClass().getClassLoader() ) )
286         {
287             for ( String s : FileUtils.getFileAndDirectoryNames( directory, "**/*.class", null, false, true, true,
288                                                                  false ) )
289             {
290                 try
291                 {
292                     String clsName = s.replace( File.separator, "." );
293                     Class<?> c = cl.loadClass( clsName.substring( 0, clsName.length() - 6 ) );
294                     WebService ann = c.getAnnotation( WebService.class );
295                     if ( !c.isInterface() && ann != null )
296                     {
297                         // more sophisticated checks are done by wsgen itself
298                         seis.add( c.getName() );
299                     }
300                 }
301                 catch ( ClassNotFoundException ex )
302                 {
303                     throw new MojoExecutionException( ex.getMessage(), ex );
304                 }
305             }
306         }
307         catch ( IOException ex )
308         {
309             throw new MojoExecutionException( ex.getMessage(), ex );
310         }
311         return seis;
312     }
313 }