1
2
3
4
5
6
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 }