View Javadoc

1   /*
2    * Copyright 2006 Guillaume Nodet.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.codehaus.mojo.jaxws;
18  
19  import java.io.File;
20  import java.io.FileFilter;
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.apache.maven.plugin.MojoExecutionException;
26  
27  import com.sun.tools.ws.wscompile.WsimportTool;
28  
29  /**
30   * <p>
31   * A Maven 2 plugin which parses wsdl and binding files and produces a corresponding object model based on the JAXWS
32   * WsImport parsing engine.
33   * </p>
34   * 
35   * @goal wsimport
36   * @phase generate-sources
37   * @requiresDependencyResolution
38   * @description JAXWS 2.x Plugin.
39   * @author gnodet <gnodet@apache.org>
40   * @author dantran <dantran@apache.org>
41   * @version $Id: WsImportMojo.java 3169 2007-01-22 02:51:29Z dantran $
42   */
43  public class WsImportMojo
44      extends AbstractJaxwsMojo
45  {
46  
47      /**
48       * The package in which the source files will be generated.
49       * 
50       * @parameter
51       */
52      private String packageName;
53  
54      /**
55       * Catalog file to resolve external entity references support TR9401, 
56       * XCatalog, and OASIS XML Catalog format.
57       * 
58       * @parameter
59       */
60      private File catalog;
61  
62      /**
63       * Set HTTP/HTTPS proxy. Format is [user[:password]@]proxyHost[:proxyPort]
64       * 
65       * @parameter
66       */
67      private String httpproxy;
68  
69      /**
70       * Directory containing wsdl files.
71       * 
72       * @parameter default-value="${basedir}/src/wsdl"
73       */
74      private File wsdlDirectory;
75  
76      /**
77       * List of files to use for wsdls. If not specified, all .wsdl files 
78       * in the wsdlDirectory will be used.
79       * 
80       * @parameter
81       */
82      protected List wsdlFiles;
83  
84      /**
85       * List of external wsdl urls.
86       * 
87       * @parameter
88       */
89      private List wsdlUrls;
90  
91      /**
92       * Directory containing binding files.
93       * 
94       * @parameter default-value="${basedir}/src/jaxws"
95       */
96      protected File bindingDirectory;
97  
98      /**
99       * List of files to use for bindings.If not specified, all .xml files 
100      * in the bindingDirectory will be used.
101      * 
102      * @parameter
103      */
104     protected List bindingFiles;
105 
106     /**
107      * @WebService.wsdlLocation and
108      * @WebServiceClient.wsdlLocation value.
109      * 
110      * @parameter
111      */
112     private String wsdlLocation;
113 
114     /**
115      * Generate code as per the given JAXWS specification version. 
116      * Version 2.0 will generate compliant code for JAXWS 2.0 spec
117      * @parameter
118      */
119     private String target;
120     
121     /**
122      * Specify where to place generated source files, keep is turned on with this option. 
123      * 
124      * @parameter default-value="${project.build.directory}/jaxws/wsimport/java"
125      */
126     protected File sourceDestDir;
127     
128     /**
129      * The location of the flag file used to determine if the output is stale.
130      * @parameter default-value="${project.build.directory}/jaxws/stale/.staleFlag"
131      */
132     private File staleFile;
133 
134     public void execute()
135         throws MojoExecutionException
136     {
137 
138         // Need to build a URLClassloader since Maven removed it form the chain
139         ClassLoader parent = this.getClass().getClassLoader();
140         String originalSystemClasspath = this.initClassLoader( parent );
141 
142         try
143         {
144 
145             sourceDestDir.mkdirs();
146             destDir.mkdirs();
147 
148             this.processWsdlViaUrls();
149 
150             this.processLocalWsdlFiles();
151 
152             // even thou the generated source already compiled, we still want to 
153             //  add the source path so that IDE can pick it up
154             project.addCompileSourceRoot( sourceDestDir.getAbsolutePath() );
155 
156         }
157         catch ( MojoExecutionException e )
158         {
159             throw e;
160         }
161         catch ( Exception e )
162         {
163             throw new MojoExecutionException( e.getMessage(), e );
164         }
165         finally
166         {
167             // Set back the old classloader
168             Thread.currentThread().setContextClassLoader( parent );
169             System.setProperty( "java.class.path", originalSystemClasspath );
170         }
171 
172     }
173 
174     /**
175      * 
176      * @throws MojoExecutionException
177      * @throws IOException
178      */
179     private void processLocalWsdlFiles()
180         throws MojoExecutionException,  IOException
181     {
182 
183         if ( isOutputStale() )
184         {
185             File[] wsdls = getWSDLFiles();
186             for ( int i = 0; i < wsdls.length; i++ )
187             {
188                 getLog().info( "Processing: " + wsdls[i].getAbsolutePath() );
189                 ArrayList<String> args = getWsImportArgs();
190                 args.add( wsdls[i].getAbsolutePath() );
191                 getLog().info( "jaxws:wsimport args: " + args );                  
192                 wsImport( args );
193             	              
194             }
195             touchStaleFile();
196         }
197 
198     }
199 
200     /**
201      * process external wsdl
202      * @throws MojoExecutionException
203      */
204     private void processWsdlViaUrls()
205         throws MojoExecutionException
206     {
207         //TODO can we do some stale check against a URL?
208         
209         for ( int i = 0; wsdlUrls != null && i < wsdlUrls.size(); i++ )
210         {
211             String wsdlUrl = wsdlUrls.get( i ).toString();
212 
213             getLog().info( "Processing: " + wsdlUrl );
214             ArrayList<String> args = getWsImportArgs();
215             args.add( wsdlUrl );
216             getLog().info( "jaxws:wsimport args: " + args );      
217             wsImport( args );
218         }
219     }
220 
221     /**
222      * Invoke wsimport compiler
223      * @param args
224      * @throws MojoExecutionException
225      */
226     private void wsImport( ArrayList<String> args )
227         throws MojoExecutionException
228     {
229         WsimportTool compTool = new WsimportTool( System.out );
230         if ( !compTool.run( args.toArray( new String[args.size()] ) ) )
231         {
232             throw new MojoExecutionException( "Error executing: wsimport " + args );
233         }
234     }
235 
236     /**
237      * 
238      * @return wsimport's command arguments
239      * @throws MojoExecutionException
240      */
241     private ArrayList<String> getWsImportArgs()
242         throws MojoExecutionException
243     {
244         ArrayList<String> args = new ArrayList<String>();
245 
246         args.add( "-s" );
247         args.add( sourceDestDir.getAbsolutePath() );
248 
249         args.add( "-d" );
250         args.add( destDir.getAbsolutePath() );
251 
252         if ( verbose )
253         {
254             args.add( "-verbose" );
255         }
256 
257         if ( httpproxy != null )
258         {
259             args.add( "-httpproxy" );
260             args.add( httpproxy );
261         }
262 
263         if ( packageName != null )
264         {
265             args.add( "-p" );
266             args.add( packageName );
267         }
268 
269         if ( catalog != null )
270         {
271             args.add( "-catalog" );
272             args.add( catalog.getAbsolutePath() );
273         }
274 
275         if ( wsdlLocation != null )
276         {
277             args.add( "-wsdllocation" );
278             args.add( wsdlLocation );
279         }
280 
281         if ( target != null )
282         {
283             args.add( "-target" );
284             args.add( target );
285         }
286         
287         if ( extension )
288         {
289             args.add( "-extension" );
290         }
291 
292         // Bindings
293         File bindings[] = getBindingFiles();
294         for ( int i = 0; i < bindings.length; i++ )
295         {
296             args.add( "-b" );
297             args.add( bindings[i].getAbsolutePath() );
298         }
299 
300         getLog().debug( "jaxws:wsimport args: " + args );
301 
302         return args;
303     }
304 
305     /**
306      * Returns a file array of xml files to translate to object models.
307      * 
308      * @return An array of schema files to be parsed by the schema compiler.
309      */
310     public final File[] getBindingFiles()
311     {
312         File [] bindings;
313         
314         if ( bindingFiles != null )
315         {
316             bindings = new File[bindingFiles.size()];
317             for ( int i = 0 ; i < bindingFiles.size(); ++i ) 
318             {
319                 String schemaName = (String) bindingFiles.get( i );
320                 bindings[i] = new File( bindingDirectory, schemaName );
321             }
322         }
323         else
324         {
325             getLog().debug( "The binding Directory is " + bindingDirectory );
326             bindings =  bindingDirectory.listFiles( new XMLFile() );
327             if ( bindings == null )
328             {
329                 bindings = new File[0];
330             }
331         }
332 
333         return bindings;
334     }
335 
336     /**
337      * Returns a file array of wsdl files to translate to object models.
338      * 
339      * @return An array of schema files to be parsed by the schema compiler.
340      */
341     public final File[] getWSDLFiles()
342     {
343         File [] files;
344 
345         if ( wsdlFiles != null )
346         {
347             files = new File[ wsdlFiles.size() ];
348             for ( int i = 0 ; i < wsdlFiles.size(); ++i ) 
349             {
350                 String schemaName = (String) wsdlFiles.get( i );
351                 files[i] = new File( wsdlDirectory, schemaName ) ;
352             }
353         }
354         else
355         {
356             getLog().debug( "The wsdl Directory is " + wsdlDirectory );
357             files = wsdlDirectory.listFiles( new WSDLFile() );
358             if ( files == null )
359             {
360                 files = new File[0];
361             }
362         }
363 
364         return files;
365     }
366 
367     /**
368      * A class used to look up .xml documents from a given directory.
369      */
370     private final class XMLFile
371         implements FileFilter
372     {
373         /**
374          * Returns true if the file ends with an xml extension.
375          * 
376          * @param file
377          *            The filed being reviewed by the filter.
378          * @return true if an xml file.
379          */
380         public boolean accept( final java.io.File file )
381         {
382             return file.getName().endsWith( ".xml" );
383         }
384     }
385 
386     /**
387      * A class used to look up .wsdl documents from a given directory.
388      */
389     private final class WSDLFile
390         implements FileFilter
391     {
392 
393         /**
394          * Returns true if the file ends with a wsdl extension.
395          * 
396          * @param file
397          *            The filed being reviewed by the filter.
398          * @return true if an wsdl file.
399          */
400         public boolean accept( final java.io.File file )
401         {
402             return file.getName().endsWith( ".wsdl" );
403         }
404 
405     }
406 
407     /**
408      * Returns true of any one of the files in the WSDL/XJB array are more new than the <code>staleFlag</code> file.
409      * 
410      * @return True if wsdl files have been modified since the last build.
411      */
412     private boolean isOutputStale()
413     {
414         File[] sourceWsdls = getWSDLFiles();
415         File[] sourceBindings = getBindingFiles();
416         boolean stale = !staleFile.exists();
417         if ( !stale )
418         {
419             getLog().debug( "Stale flag file exists, comparing to wsdls and bindings." );
420             long staleMod = staleFile.lastModified();
421 
422             for ( int i = 0; i < sourceWsdls.length; i++ )
423             {
424                 if ( sourceWsdls[i].lastModified() > staleMod )
425                 {
426                     getLog().debug( sourceWsdls[i].getName() + " is newer than the stale flag file." );
427                     stale = true;
428                 }
429             }
430 
431             for ( int i = 0; i < sourceBindings.length; i++ )
432             {
433                 if ( sourceBindings[i].lastModified() > staleMod )
434                 {
435                     getLog().debug( sourceBindings[i].getName() + " is newer than the stale flag file." );
436                     stale = true;
437                 }
438             }
439         }
440         return stale;
441     }
442 
443     private void touchStaleFile()
444         throws IOException
445     {
446         if ( !staleFile.exists() )
447         {
448             staleFile.getParentFile().mkdirs();
449             staleFile.createNewFile();
450             getLog().debug( "Stale flag file created." );
451         }
452         else
453         {
454             staleFile.setLastModified( System.currentTimeMillis() );
455         }
456     }
457 
458 }