View Javadoc

1   /*
2    * Copyright (C) The MetaClass Group. All rights reserved.
3    *
4    * This software is published under the terms of the Spice
5    * Software License version 1.1, a copy of which has been included
6    * with this distribution in the LICENSE.txt file.
7    */
8   package org.codehaus.metaclass.tools.tasks;
9   
10  import java.io.File;
11  import java.util.ArrayList;
12  import java.util.Collection;
13  import java.util.Iterator;
14  import java.util.List;
15  import org.apache.tools.ant.AntClassLoader;
16  import org.apache.tools.ant.BuildException;
17  import org.apache.tools.ant.DirectoryScanner;
18  import org.apache.tools.ant.Project;
19  import org.apache.tools.ant.Task;
20  import org.apache.tools.ant.types.FileSet;
21  import org.apache.tools.ant.types.Path;
22  import org.codehaus.metaclass.io.MetaClassIOASM;
23  import org.codehaus.metaclass.io.MetaClassIOBinary;
24  import org.codehaus.metaclass.io.MetaClassIOXml;
25  import org.codehaus.metaclass.model.ClassDescriptor;
26  import org.codehaus.metaclass.tools.compiler.ClassDescriptorCompiler;
27  import org.codehaus.metaclass.tools.compiler.CompilerMonitor;
28  import org.codehaus.metaclass.tools.compiler.JavaClassFilter;
29  import org.codehaus.metaclass.tools.qdox.NonNamespaceAttributeRemovingInterceptor;
30  import org.codehaus.metaclass.tools.qdox.QDoxAttributeInterceptor;
31  
32  /***
33   * A Task to generate Attributes descriptors from source files.
34   * 
35   * @author Peter Donald
36   * @version $Revision: 1.21 $ $Date: 2004/01/16 02:07:29 $
37   */
38  public class GenerateClassDescriptorsTask
39      extends Task
40      implements CompilerMonitor
41  {
42      /*** Constant indicating should write out binary descriptors. */
43      public static final int CLASS_TYPE = 0;
44  
45      /*** Constant indicating should write out binary descriptors. */
46      public static final int BINARY_TYPE = 1;
47  
48      /*** Constant indicating should write out serialized xml descriptors. */
49      public static final int XML_TYPE = 2;
50  
51      /*** Destination directory */
52      private File m_destDir;
53  
54      /*** Variable that indicates the output type. See above constants. */
55      private int m_format = CLASS_TYPE;
56  
57      /*** Flag indicating whether the compacter should methods with no attributes. */
58      private boolean m_keepEmptyMethods = false;
59  
60      /*** Variable that indicates whether non-namespaced tags are filtered out. */
61      private boolean m_namespaceTagsOnly = true;
62  
63      /*** Internal list of filter elements added by user. */
64      private final FilterSet m_filterSet = new FilterSet();
65  
66      /*** Internal list of interceptor elements added by user. */
67      private final InterceptorSet m_interceptorSet = new InterceptorSet();
68  
69      /*** Flag set to true if writing a descriptor fails. */
70      private boolean m_failed;
71  
72      /*** Compiler used to compile descriptors. */
73      private final ClassDescriptorCompiler m_compiler = new ClassDescriptorCompiler();
74  
75      /*** List of filesets to process. */
76      private final List m_filesets = new ArrayList();
77  
78      /***
79       * Setup project for task.
80       * 
81       * @param project the project
82       */
83      public void setProject( final Project project )
84      {
85          super.setProject( project );
86          m_filterSet.setProject( project );
87          m_interceptorSet.setProject( project );
88      }
89  
90      /***
91       * Add a filter definition that will create filter to process metadata.
92       * 
93       * @param element the filter definition
94       */
95      public void addFilter( final PluginElement element )
96      {
97          m_filterSet.addFilter( element );
98      }
99  
100     /***
101      * Add a filter definition set.
102      * 
103      * @param set a filter definition set.
104      */
105     public void addFilterSet( final FilterSet set )
106     {
107         m_filterSet.addFilterSet( set );
108     }
109 
110     /***
111      * Add an interceptor definition that will create interceptor to process
112      * metadata.
113      * 
114      * @param element the interceptor definition
115      */
116     public void addInterceptor( final PluginElement element )
117     {
118         m_interceptorSet.addInterceptor( element );
119     }
120 
121     /***
122      * Add an interceptor definition set.
123      * 
124      * @param set the interceptor set
125      */
126     public void addInterceptorSet( final InterceptorSet set )
127     {
128         m_interceptorSet.addInterceptorSet( set );
129     }
130 
131     /***
132      * Add fileset to list of files to be processed.
133      * 
134      * @param fileSet fileset to list of files to be processed.
135      */
136     public void addFileset( final FileSet fileSet )
137     {
138         m_filesets.add( fileSet );
139     }
140 
141     /***
142      * Set the destination directory for generated files.
143      * 
144      * @param destDir the destination directory for generated files.
145      */
146     public void setDestDir( final File destDir )
147     {
148         m_destDir = destDir;
149     }
150 
151     /***
152      * Specify the output format. Must be one of xml or serialized.
153      * 
154      * @param format the output format
155      */
156     public void setFormat( final FormatEnum format )
157     {
158         m_format = format.getTypeCode();
159     }
160 
161     /***
162      * Set flag indicating whether Compacter should keep empty methods.
163      * 
164      * @param keepEmptyMethods the flag
165      */
166     public void setKeepEmptyMethods( final boolean keepEmptyMethods )
167     {
168         m_keepEmptyMethods = keepEmptyMethods;
169     }
170 
171     /***
172      * Set the flag whether non-namespaced tags are filtered out.
173      * 
174      * @param namespaceTagsOnly true to filter out non-namespaced tags
175      */
176     public void setNamespaceTagsOnly( final boolean namespaceTagsOnly )
177     {
178         m_namespaceTagsOnly = namespaceTagsOnly;
179     }
180 
181     /***
182      * Generate classes and output.
183      */
184     public void execute()
185     {
186         setupFilters();
187         setupInterceptors();
188 
189         if( m_namespaceTagsOnly )
190         {
191             m_compiler.
192                 addInterceptor(
193                     NonNamespaceAttributeRemovingInterceptor.INTERCEPTOR );
194         }
195 
196         m_compiler.setDestDir( m_destDir );
197         m_compiler.setMonitor( this );
198         m_compiler.setKeepEmptyMethods( m_keepEmptyMethods );
199 
200         setupTarget();
201 
202         setupFileList();
203 
204         try
205         {
206             m_compiler.execute();
207         }
208         catch( final Exception e )
209         {
210             throw new BuildException( e.getMessage() );
211         }
212         if( m_failed )
213         {
214             final String message = "Error generating ClassDescriptors";
215             throw new BuildException( message );
216         }
217     }
218 
219     /***
220      * Setup list of files compiler will compile.
221      */
222     private void setupFileList()
223     {
224         final int count = m_filesets.size();
225         for( int i = 0; i < count; i++ )
226         {
227             final FileSet fileSet = (FileSet)m_filesets.get( i );
228             appendFileSetToCompiler( fileSet );
229         }
230     }
231 
232     /***
233      * Add all files contained in fileset to compilers file list.
234      * 
235      * @param fileSet the fileset
236      */
237     private void appendFileSetToCompiler( final FileSet fileSet )
238     {
239         final File dir = fileSet.getDir( getProject() );
240         final DirectoryScanner directoryScanner =
241             fileSet.getDirectoryScanner( getProject() );
242         directoryScanner.scan();
243         final String[] includedFiles = directoryScanner.getIncludedFiles();
244         for( int j = 0; j < includedFiles.length; j++ )
245         {
246             final File file = new File( dir, includedFiles[ j ] );
247             m_compiler.addSourceFile( file );
248         }
249     }
250 
251     /***
252      * Setup the output target of compiler.
253      */
254     void setupTarget()
255     {
256         if( CLASS_TYPE == m_format )
257         {
258             m_compiler.setMetaClassIO( MetaClassIOASM.IO );
259         }
260         else if( BINARY_TYPE == m_format )
261         {
262             m_compiler.setMetaClassIO( MetaClassIOBinary.IO );
263         }
264         else
265         {
266             m_compiler.setMetaClassIO( MetaClassIOXml.IO );
267         }
268     }
269 
270     /***
271      * Creat filters and add them to compiler.
272      */
273     private void setupFilters()
274     {
275         final Collection collection = m_filterSet.toPlugins();
276         log( "Using " + collection.size() + " Filters", Project.MSG_VERBOSE );
277         final Iterator iterator = collection.iterator();
278         while( iterator.hasNext() )
279         {
280             final PluginElement element = (PluginElement)iterator.next();
281             final JavaClassFilter filter = (JavaClassFilter)
282                 createInstance( element,
283                                 JavaClassFilter.class,
284                                 "filter" );
285             log( "Adding Filter " + filter, Project.MSG_DEBUG );
286             m_compiler.addFilter( filter );
287         }
288     }
289 
290     /***
291      * Build the interceptors and add them to the compiler.
292      */
293     private void setupInterceptors()
294     {
295         final Collection collection = m_interceptorSet.toPlugins();
296         log( "Using " + collection.size() + " Interceptors",
297              Project.MSG_VERBOSE );
298         final Iterator iterator = collection.iterator();
299         while( iterator.hasNext() )
300         {
301             final PluginElement element = (PluginElement)iterator.next();
302             final QDoxAttributeInterceptor interceptor = (QDoxAttributeInterceptor)
303                 createInstance( element,
304                                 QDoxAttributeInterceptor.class,
305                                 "interceptor" );
306             log( "Adding Interceptor " + interceptor, Project.MSG_DEBUG );
307             m_compiler.addInterceptor( interceptor );
308         }
309     }
310 
311     /***
312      * Create an instance of a plugin object.
313      * 
314      * @param element the plugin def
315      * @param type the expected type
316      * @param description the description of type
317      * @return the instance of type
318      */
319     Object createInstance( final PluginElement element,
320                            final Class type,
321                            final String description )
322     {
323         final String name = element.getName();
324         final AntClassLoader loader = createLoader( element );
325 
326         try
327         {
328             final Object object = loader.loadClass( name ).newInstance();
329             if( !type.isInstance( object ) )
330             {
331                 final String message =
332                     "Error creating " +
333                     description +
334                     " " +
335                     name +
336                     " as it does not implement " + type.getName() + ".";
337                 log( message );
338                 throw new BuildException( message );
339             }
340             return object;
341         }
342         catch( final Exception e )
343         {
344             final String message = "Error creating " +
345                                    description +
346                                    " " +
347                                    name;
348             log( message );
349             throw new BuildException( message, e );
350         }
351     }
352 
353     /***
354      * Create Loader for PLuginElement.
355      * 
356      * @param element the element
357      * @return the loader
358      */
359     private AntClassLoader createLoader( final PluginElement element )
360     {
361         Path path = element.getPath();
362         if( null == path )
363         {
364             path = new Path( getProject() );
365         }
366 
367         return new AntClassLoader( getClass().getClassLoader(),
368                                    getProject(),
369                                    path,
370                                    true );
371     }
372 
373     /***
374      * Return a description of output format to print as debug message.
375      * 
376      * @return the output formats descriptive name
377      */
378     final String getOutputDescription()
379     {
380         if( XML_TYPE == m_format )
381         {
382             return "xml";
383         }
384         else
385         {
386             return "binary";
387         }
388     }
389 
390     /***
391      * Print error message and flag task as having failed.
392      * 
393      * @param descriptor the descriptor
394      * @param e the exception
395      */
396     public void errorWritingDescriptor( final ClassDescriptor descriptor,
397                                         final Exception e )
398     {
399         log( "Error writing descriptor for " +
400              descriptor.getName() + " due to " + e,
401              Project.MSG_ERR );
402         m_failed = true;
403     }
404 
405     /***
406      * Print error message and flag task as having failed.
407      * 
408      * @param file the source file
409      */
410     public void missingSourceFile( final File file )
411     {
412         log( "Missing Source file " + file, Project.MSG_ERR );
413         m_failed = true;
414     }
415 
416     /***
417      * * @see CompilerMonitor#javaClassObjectsLoaded
418      */
419     public void javaClassObjectsLoaded( final Collection classes )
420     {
421         log( "Loaded " + classes.size() + " Java classes.",
422              Project.MSG_DEBUG );
423     }
424 
425     /***
426      * * @see CompilerMonitor#postFilterJavaClassList
427      */
428     public void postFilterJavaClassList( final Collection classes )
429     {
430         log( "MetaClass Attributes Compiler building " +
431              classes.size() + " " + getOutputDescription() + " descriptors.",
432              Project.MSG_DEBUG );
433     }
434 
435     /***
436      * @see CompilerMonitor#postBuildDescriptorsList
437      */
438     public void postBuildDescriptorsList( final Collection descriptors )
439     {
440     }
441 
442     /***
443      * @see CompilerMonitor#postCompactDescriptorsList
444      */
445     public void postCompactDescriptorsList( final Collection descriptors )
446     {
447         log( "MetaClass Attributes Compiler writing " +
448              descriptors.size() +
449              " " +
450              getOutputDescription() +
451              " descriptors.", Project.MSG_INFO );
452     }
453 
454     /***
455      * @see CompilerMonitor#errorGeneratingDescriptor
456      */
457     public void errorGeneratingDescriptor( final String classname,
458                                            final Throwable t )
459     {
460         log( "Error Generating decriptor for  " +
461              classname +
462              ". Reason: " + t, Project.MSG_ERR );
463         m_failed = true;
464     }
465 
466     /***
467      * Return the Compiler used to create descriptors.
468      * 
469      * @return the Compiler used to create descriptors.
470      */
471     protected final ClassDescriptorCompiler getCompiler()
472     {
473         return m_compiler;
474     }
475 }