View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2004 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id: CastorSourceGenTask.java 6410 2006-11-17 12:06:24Z wguttmn $
44   */
45  package org.castor.anttask;
46  
47  import java.io.File;
48  import java.io.FileInputStream;
49  import java.io.FileNotFoundException;
50  import java.io.IOException;
51  import java.lang.reflect.InvocationTargetException;
52  import java.lang.reflect.Method;
53  import java.util.Properties;
54  import java.util.Vector;
55  
56  import org.apache.tools.ant.BuildException;
57  import org.apache.tools.ant.DirectoryScanner;
58  import org.apache.tools.ant.taskdefs.MatchingTask;
59  import org.apache.tools.ant.types.FileSet;
60  import org.castor.xml.BackwardCompatibilityContext;
61  import org.castor.xml.InternalContext;
62  import org.exolab.castor.builder.SourceGenerator;
63  import org.exolab.castor.builder.binding.ExtendedBinding;
64  import org.exolab.castor.builder.factory.FieldInfoFactory;
65  import org.exolab.castor.xml.XMLException;
66  import org.exolab.castor.xml.schema.Schema;
67  import org.exolab.castor.xml.schema.SchemaContext;
68  import org.exolab.castor.xml.schema.SchemaContextImpl;
69  import org.exolab.castor.xml.schema.reader.Sax2ComponentReader;
70  import org.exolab.castor.xml.schema.reader.SchemaUnmarshaller;
71  import org.exolab.javasource.JClass;
72  import org.xml.sax.InputSource;
73  import org.xml.sax.Parser;
74  import org.xml.sax.SAXException;
75  
76  /**
77   * An <a href="http://ant.apache.org/">Ant</a> task to call the Castor
78   * Source Generator. It can be passed a file, a directory, a Fileset or all
79   * three.
80   *
81   * @author <a href="mailto:joel.farquhar@montage-dmc.com">Joel Farquhar</a>
82   * @author <a href="mailto:ferret AT frii DOT com">Bruce Snyder</a>
83   * @author <a href="mailto:wguttmn AT codehaus DOT org">Werner Guttmann</a>
84   * @version $Revision: 6543 $ $Date: 2005-03-05 06:42:06 -0700 (Sat, 05 Mar 2005) $
85   */
86  public final class CastorCodeGenTask extends MatchingTask {
87  
88      /** Message indicating that the method setJdoDescriptorCreation cannot be invoked. */
89      private static final String PROBLEM_SETTING_JDO_DESC = 
90          "Problem calling SourceGenerator.setJdoDescriptorCreation: ";
91  
92      /** Msg indicating class descriptor generation has been disabled. */
93      private static final String DISABLE_DESCRIPTORS_MSG =
94          "Disabling generation of Class descriptors";
95      
96      /** Msg indicating marshaling framework code will not be generated. */
97      private static final String DISABLE_MARSHAL_MSG =
98          "Disabling generation of Marshaling framework methods (marshal, unmarshal, validate).";
99      
100     /** Msg indicating that castor-testable code will be generated. */
101     private static final String CASTOR_TESTABLE_MSG =
102         "The generated classes will implement org.exolab.castor.tests.CastorTestable";
103     
104     /** Error message -- invalid line seperator. */
105     private static final String INVALID_LINESEP_MSG =
106         "Invalid value for lineseparator, must be win, unix, or mac.";
107     
108     /** Error message -- no schemas to run code generator on. */
109     private static final String NO_SCHEMA_MSG =
110         "At least one of the file, url or dir attributes, or a fileset element, must be set.";
111 
112     /** Castor XML context - the mother of all. */
113     private InternalContext _internalContext;
114     
115     /** If processing one schema file, this lists the file. */
116     private File _schemaFile = null;
117     
118     /** If processing one schema file from an URL, this lists the file. */
119     private String _schemaURL = null;
120     
121     /** If processing all schemas in a directory, this lists the directory. */
122     private File _schemaDir = null;
123     
124     /** If processing a fileset, this lists the fileset. */
125     private Vector < FileSet > _schemaFilesets = new Vector < FileSet > ();
126 
127     // Begin Source Generator parameters
128     /** The package that generated code will belong to. */
129     private String _srcpackage;
130     
131     /** The directory that code will be generated into. */
132     private String _todir;
133 
134     /** The directory that resources will be generated into, if specified. */
135     private String _resourcesDirectory;
136 
137     /** Binding file for the code generator. */
138     private String _bindingfile;
139     
140     /** Information about how to generate collections. */
141     private String _types;
142     
143     /** Line seperator to use for generated code. */
144     private String _lineseparator;
145     
146     /** If true, the code generator will be verbose. */
147     private boolean _verbose;
148     
149     /** If true, non-fatal warnings will be suppressed.  Also, existing source
150      *  files will be silently overwritten. */
151     private boolean _warnings = true;
152     
153     /** If true, class descriptors will not be generated. */
154     private boolean _nodesc;
155     
156     /** If true, marshaling code will not be generated. */
157     private boolean _nomarshal;
158 
159     /** If true, old Java field naming conventions will be used. */
160     private boolean _useOldFieldNaming = true;
161 
162     /**
163      * If true, a mapping file will be generated (additionally).
164      */
165     private boolean _generateMapping;
166     
167     /** If true, Castor's CTF testable framework code will be generated. */
168     private boolean _testable;
169     
170     /** Whether to generate code for imported schemas, too. */
171     private boolean _generateImportedSchemas;
172     
173     /** Whether to generate SAX-1 compliant code. */
174     private boolean _sax1;
175     
176     /** Whether enumerated type lookup should be performed in a case insensitive manner. */
177     private boolean _caseInsensitive;
178     
179     /** CastorBuilderProperties file. */
180     private String _properties;
181     
182     /** The name conflict strategy to use. */
183     private String _nameConflictStrategy = "warnViaConsoleDialog";
184     
185     /** Name of the automatic clas name conflict strategy to use. */
186     private String _automaticConflictStrategy = "xpath";
187 
188     /** Whether to generate JDO descriptors. */
189     private boolean _generateJdoDescriptors;
190 
191     /**
192      * Mode for printing JClass instances.
193      */
194     private String _jclassPrinterType = "standard";
195     
196     /** SourceGenerator instance. */
197     private SourceGenerator _sgen;
198 
199     /**
200      * No-arg constructor.
201      */
202     public CastorCodeGenTask() {
203         super();
204         _internalContext = new BackwardCompatibilityContext();
205     }
206 
207     /**
208      * Sets the individual schema that will have code generated for it.
209      * 
210      * @param file One schema file.
211      */
212     public void setFile(final File file) {
213         _schemaFile = file;
214     }
215 
216     /**
217      * Sets an URL for one individual schema that will have code generated for it.
218      * 
219      * @param schemaURL URL for one schema file.
220      */
221     public void setSchemaURL(final String schemaURL) {
222         _schemaURL = schemaURL;
223     }
224 
225 
226     /**
227      * Sets the directory such that all schemas in this directory will have code
228      * generated for them.
229      * 
230      * @param dir The directory containing schemas to process.
231      */
232     public void setDir(final File dir) {
233         _schemaDir = dir;
234     }
235 
236     /**
237      * Adds a fileset to process that contains schemas to process.
238      * 
239      * @param set An individual file set containing schemas.
240      */
241     public void addFileset(final FileSet set) {
242         _schemaFilesets.addElement(set);
243     }
244 
245     /**
246      * Sets the package that generated code will belong to.
247      * 
248      * @param pack The package that generated code will belong to.
249      */
250     public void setPackage(final String pack) {
251         _srcpackage = pack;
252     }
253 
254     /**
255      * Sets the directory into which code will be generated.
256      * 
257      * @param dest The directory into which code will be generated.
258      */
259     public void setTodir(final String dest) {
260         _todir = dest;
261     }
262 
263     /**
264      * Sets the directory into which resources will be generated. If not 
265      * specified, resources will be generated in the same location as 
266      * code.
267      * 
268      * @param dest The directory into which resources will be generated.
269      */
270     public void setResourcesDirectory(final String destination) {
271         _resourcesDirectory = destination;
272     }
273 
274     /**
275      * Sets the binding file to be used for code generation.
276      * 
277      * @param bindingfile The binding file to be used for code generation.
278      */
279     public void setBindingfile(final String bindingfile) {
280         _bindingfile = bindingfile;
281     }
282 
283     /**
284      * Sets the line seperator to use for code generation.
285      * 
286      * @param ls The line seperator to use for code generation.
287      */
288     public void setLineseparator(final String ls) {
289         _lineseparator = ls;
290     }
291 
292     /**
293      * Sets the type factory for code generation.
294      * 
295      * @param tf The type factory to use for code generation.
296      */
297     public void setTypes(final String tf) {
298         _types = (tf.equals("j2")) ? "arraylist" : tf;
299     }
300 
301     /**
302      * Sets whether or not code generation gives extra information about its work.
303      * 
304      * @param b If true, the code generator will be verbose.
305      */
306     public void setVerbose(final boolean b) {
307         _verbose = b;
308     }
309 
310     /**
311      * Sets the name conflict strategy to use.
312      * 
313      * @param nameConflictStrategy The name conflict strategy to use
314      */
315     public void setNameConflictStrategy(final String nameConflictStrategy) {
316         _nameConflictStrategy = nameConflictStrategy;
317     }
318 
319     /**
320      * Sets the name conflict strategy to use.
321      * 
322      * @param automaticConflictStrategy The automatic class name conflict strategy to use
323      */
324     public void setAutomaticConflictStrategy(final String automaticConflictStrategy) {
325         _automaticConflictStrategy = automaticConflictStrategy;
326     }
327 
328     
329     /**
330      * Sets whether or not non-fatal warnings should be suppressed.
331      * 
332      * @param b If true, non-fatal warnings will be suppressed. This additionally
333      *        means that existing source files will be silently overwritten.
334      */
335     public void setWarnings(final boolean b) {
336         _warnings = b;
337     }
338 
339     /**
340      * Sets whether or not the old Java field naming conventions should be used.
341      * 
342      * @param useOldFieldNaming If true, the old Java field naming conventions will be used.
343      */
344     public void setUseOldFieldNaming(final boolean useOldFieldNaming) {
345         _useOldFieldNaming = useOldFieldNaming;
346     }
347 
348     /**
349      * Sets whether or not class descriptors are generated.
350      * 
351      * @param b If true, class descriptors are generated.
352      */
353     public void setNodesc(final boolean b) {
354         _nodesc = b;
355     }
356 
357     /**
358      * Sets whether or not marshaling methods are generated.
359      * 
360      * @param b If true, marshaling methods are generated.
361      */
362     public void setNomarshal(final boolean b) {
363         _nomarshal = b;
364     }
365 
366     /**
367      * Sets whether CTF framework code is generated.
368      * 
369      * @param b If true, the generated code will be instrumented for the CTF.
370      */
371     public void setTestable(final boolean b) {
372         _testable = b;
373     }
374 
375     /**
376      * Controls whether to generate code for imported schemas as well.
377      * 
378      * @param generateImportedSchemas True if code should be generated for imported schemas.
379      */
380     public void setGenerateImportedSchemas(final boolean generateImportedSchemas) {
381         _generateImportedSchemas = generateImportedSchemas;
382     }
383 
384     /**
385      * Controls whether to generate JDO-specific class descriptors.
386      * 
387      * @param generateJdoDescriptors True if JDP class descriptors should be generated
388      */
389     public void setGenerateJdoDescriptors(final boolean generateJdoDescriptors) {
390         _generateJdoDescriptors = generateJdoDescriptors;
391     }
392 
393 
394     /**
395      * Controls whether to generate SAX-1 compliant code.
396      * 
397      * @param sax1 True if SAX-1 compliant code should be generated.
398      */
399     public void setSAX1(final boolean sax1) {
400         _sax1 = sax1;
401     }
402 
403     /**
404      * Controls whether enumerated type lookup should be performed in a case
405      * insensitive manner.
406      * 
407      * @param caseInsensitive True if enumerated type lookup should be performed in a case
408      *        insensitive manner
409      */
410     public void setCaseInsensitive(final boolean caseInsensitive) {
411         _caseInsensitive = caseInsensitive;
412     }
413 
414     /**
415      * Sets the file to use for castor builder properties.
416      *
417      * @param properties The properties to use.
418      */
419     public void setProperties(final String properties) {
420         _properties = properties;
421     }
422     
423     /**
424      * Sets the mode for printing {@link JClass} instances.
425      * @param jclassPrinterType The mode for printing {@link JClass} instances.
426      */
427     public void setJClassPrinterType(final String jclassPrinterType) {
428         _jclassPrinterType = jclassPrinterType;
429     }
430 
431     /**
432      * Controls whether a mapping file should (additionally) be generated.
433 
434      * @param generateMapping True if a mapping file should be generated.
435      */
436     public void setGenerateMapping(final boolean generateMapping) {
437         _generateMapping = generateMapping;
438     }
439 
440     /**
441      * Configured the code generator. If anything goes wrong during configuration of the
442      * Ant task a BuildException will be thrown.
443      */
444     private void config() {
445         // Create Source Generator with appropriate type factory
446         if (_types != null) {
447             FieldInfoFactory factory;
448             try {
449                if (_useOldFieldNaming) {
450                   factory = new FieldInfoFactory(_types);
451                } else {
452                   factory = new FieldInfoFactory(_types, false);
453                }
454 
455                _sgen = new CastorSourceGeneratorWrapper(factory);
456             } catch (Exception e) {
457                 try {
458                     factory = (FieldInfoFactory) Class.forName(_types).newInstance();
459                     _sgen = new CastorSourceGeneratorWrapper(factory);
460                 } catch (Exception e2) {
461                     throw new BuildException("Invalid types \"" + _types + "\": " + e.getMessage());
462                 }
463             }
464         } else {
465             // default
466             _sgen = new CastorSourceGeneratorWrapper();
467         }
468 
469         // Set Line Separator
470         String lineSep = System.getProperty("line.separator");
471         if (_lineseparator != null) {
472             if ("win".equals(_lineseparator)) {
473                 log("Using Windows style line separation.");
474                 lineSep = "\r\n";
475             } else if ("unix".equals(_lineseparator)) {
476                 log("Using UNIX style line separation.");
477                 lineSep = "\n";
478             } else if ("mac".equals(_lineseparator)) {
479                 log("Using Macintosh style line separation.");
480                 lineSep = "\r";
481             } else {
482                 throw new BuildException(INVALID_LINESEP_MSG);
483             }
484         }
485         _sgen.setLineSeparator(lineSep);
486 
487         _sgen.setDestDir(_todir);
488         
489         // TODO: use reflection to invoke this
490         if (_resourcesDirectory != null && _resourcesDirectory.length() > 0) {
491             _sgen.setResourceDestination(_resourcesDirectory);
492         }
493 
494         if (_bindingfile != null) { _sgen.setBinding(_bindingfile); }
495 
496         _sgen.setVerbose(_verbose);
497         _sgen.setSuppressNonFatalWarnings(!_warnings);
498 
499         _sgen.setDescriptorCreation(!_nodesc);
500         if (_nodesc) { log(DISABLE_DESCRIPTORS_MSG); }
501 
502         _sgen.setCreateMarshalMethods(!_nomarshal);
503         if (_nomarshal) { log(DISABLE_MARSHAL_MSG); }
504 
505         _sgen.setGenerateImportedSchemas(_generateImportedSchemas);
506 
507         _sgen.setSAX1(_sax1);
508 
509         _sgen.setCaseInsensitive(_caseInsensitive);
510         
511         _sgen.setNameConflictStrategy(_nameConflictStrategy);
512         
513         _sgen.setClassNameConflictResolver(_automaticConflictStrategy);
514         
515         _sgen.setJClassPrinterType(_jclassPrinterType);
516         
517         _sgen.setGenerateMappingFile(_generateMapping);
518         
519         if (_generateJdoDescriptors) {
520             callSetterMethodUsingReflection(_sgen, "setJdoDescriptorCreation",
521                     boolean.class, new Boolean(_generateJdoDescriptors));
522         }
523 
524         _sgen.setTestable(_testable);
525         if (this._testable) { log(CASTOR_TESTABLE_MSG); }
526 
527         // Set Builder Properties;
528         if (_properties != null) {
529             String filePath = new File(_properties).getAbsolutePath();
530             Properties customProperties = new Properties();
531             try {
532                 customProperties.load(new FileInputStream(filePath));
533             } catch (FileNotFoundException e) {
534                 throw new BuildException("Properties file \"" + filePath + "\" not found");
535             } catch (IOException e) {
536                 throw new BuildException("Can't read properties file \"" + filePath + "\": " + e);
537             }
538             _sgen.setDefaultProperties(customProperties);
539         }
540     }
541 
542     /**
543      * Runs source generation. If anything goes wrong during source generation a
544      * BuildException will be thrown.
545      * 
546      * @param filePath an individual Schema to generate code for.
547      */
548     private void processFile(final String filePath) {
549         log("Processing " + filePath);
550         try {
551             _sgen.generateSource(filePath, _srcpackage);
552         } catch (FileNotFoundException e) {
553             String message = "XML Schema file \"" + _schemaFile.getAbsolutePath() + "\" not found.";
554             log(message);
555             throw new BuildException(message);
556         } catch (Exception iox) {
557             throw new BuildException(iox);
558         }
559     }
560 
561     /**
562      * Runs source generation on a XML schema instance pointed to by an URL. If anything 
563      * goes wrong during source generation a BuildException will be thrown.
564      * 
565      * @param schemaURL An URL to an individual XML schema to generate code for.
566      */
567     private void processURL(final String schemaURL) {
568         log("Processing " + schemaURL);
569         try {
570             InputSource inputSource = new InputSource(schemaURL);
571             _sgen.generateSource(inputSource, _srcpackage);
572         } catch (FileNotFoundException e) {
573             String message = "XML Schema file \"" + _schemaURL + "\" not found.";
574             log(message);
575             throw new BuildException(message);
576         } catch (Exception iox) {
577             throw new BuildException(iox);
578         }
579     }
580 
581     /**
582      * Public execute method -- entry point for the Ant task.  Loops over all
583      * schema that need code generated and creates needed code generators, then
584      * executes them. If anything goes wrong during execution of the Ant task a
585      * BuildException will be thrown.
586      * 
587      * @see org.apache.tools.ant.Task#execute()
588      */
589     public void execute() {
590         // Must have something to run the source generator on
591         if (_schemaFile == null && _schemaDir == null && _schemaFilesets.size() == 0
592                 && _schemaURL == null) {
593             throw new BuildException(NO_SCHEMA_MSG);
594         }
595 
596         try {
597             config();
598 
599             // Run source generator on file
600             if (_schemaFile != null) {
601                 processFile(_schemaFile.getAbsolutePath());
602             }
603 
604             // Run source generator on all files in directory
605             if (_schemaDir != null && _schemaDir.exists() && _schemaDir.isDirectory()) {
606                 DirectoryScanner ds = this.getDirectoryScanner(_schemaDir);
607 
608                 String[] files = ds.getIncludedFiles();
609                 for (int i = 0; i < files.length; i++) {
610                     String filePath = _schemaDir.getAbsolutePath() + File.separator + files[i];
611                     processFile(filePath);
612                 }
613             }
614 
615             // Run source generator on all files in FileSet
616             for (int i = 0; i < _schemaFilesets.size(); i++) {
617                 FileSet fs = (FileSet) _schemaFilesets.elementAt(i);
618                 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
619                 File subdir = fs.getDir(getProject());
620 
621                 String[] files = ds.getIncludedFiles();
622                 for (int j = 0; j < files.length; j++) {
623                     String filePath = subdir.getAbsolutePath() + File.separator + files[j];
624                     processFile(filePath);
625                 }
626             }
627 
628             // Run source generator on URL for XML schema
629             if (_schemaURL != null) {
630                 processURL(_schemaURL);
631             }
632         } finally {
633             _sgen = null;
634         }
635     }
636 
637     /**
638      * Override Castor's SourceGenerator to inject exception handling.
639      * Code based on castor-0.9.5.3-xml.jar.
640      */
641     private final class CastorSourceGeneratorWrapper extends SourceGenerator {
642         /**
643          * No-arg constructor.
644          */
645         public CastorSourceGeneratorWrapper() {
646             super();
647         }
648 
649         /**
650          * Constructs a source generator with the provided FieldInfoFactory.
651          * 
652          * @param fieldInfoFactory A FieldInfoFactory to use for collections.
653          */
654         public CastorSourceGeneratorWrapper(final FieldInfoFactory fieldInfoFactory) {
655             super(fieldInfoFactory);
656         }
657 
658         /**
659          * Constructs a source generator with the provided FieldInfoFactory and
660          * binding file.
661          * 
662          * @param fieldInfoFactory a FieldInfoFactory to use for collections.
663          * @param extendedBinding binding information for the code generator.
664          */
665         public CastorSourceGeneratorWrapper(
666                 final FieldInfoFactory fieldInfoFactory, final ExtendedBinding extendedBinding) {
667             super(fieldInfoFactory, extendedBinding);
668         }
669 
670         /**
671          * Generate source. If anything goes wrong during generation of source a
672          * BuildException will be thrown.
673          *
674          * @param source an individual schema to process.
675          * @param packageName the package name for generated code.
676          * 
677          * @see org.exolab.castor.builder.SourceGenerator
678          *      #generateSource(org.xml.sax.InputSource, java.lang.String)
679          */
680         public void generateSource(final InputSource source, final String packageName) {
681             Parser parser = null;
682             try {
683                 parser = _internalContext.getParser();
684             } catch (RuntimeException e) {
685                 throw new BuildException("Unable to create SAX parser.", e);
686             }
687             if (parser == null) {
688                 throw new BuildException("Unable to create SAX parser.");
689             }
690 
691             SchemaContext schemaContext = new SchemaContextImpl();
692             SchemaUnmarshaller schemaUnmarshaller = null;
693             try {
694                 schemaUnmarshaller = new SchemaUnmarshaller(schemaContext);
695             } catch (XMLException e) {
696                 throw new BuildException("Unable to create schema unmarshaller.", e);
697             }
698 
699             Sax2ComponentReader handler = new Sax2ComponentReader(schemaUnmarshaller);
700             parser.setDocumentHandler(handler);
701             parser.setErrorHandler(handler);
702             try {
703                 parser.parse(source);
704             } catch (IOException e) {
705                 String msg = "Can't read input file " + source.getSystemId() + ".\n" + e;
706                 throw new BuildException(msg, e);
707             } catch (SAXException e) {
708                 String msg = "Can't parse input file " + source.getSystemId() + ".\n" + e;
709                 throw new BuildException(msg, e);
710             }
711             Schema schema = schemaUnmarshaller.getSchema();
712             try {
713                 generateSource(schema, packageName);
714             } catch (Exception iox) {
715                 throw new BuildException(iox);
716             }
717         }
718     }
719     
720     /**
721      * Helper method to invoke a setter method on {@link SourceGenerator} that might not 
722      * be available due to a version issue.
723      * 
724      * @param sgen {@link SourceGenerator} instance
725      * @param methodName Name of the method
726      * @param parameterType Type of the method parameter.
727      * @param parameterValue Actual parameter value to be used during method invocation.
728      * @throws BuildException If the method cannot be invoked.
729      */
730     private void callSetterMethodUsingReflection(final SourceGenerator sgen,
731             final String methodName, final Class parameterType,
732             final Object parameterValue) throws BuildException {
733         try {
734             Method method = sgen.getClass().getMethod(methodName,
735                     new Class[] {parameterType});
736             method.invoke(sgen, new Object[] {parameterValue});
737         } catch (NoSuchMethodException e) {
738             // unable to find method to configure JDO descriptor creation.
739         } catch (IllegalArgumentException e) {
740             throw new BuildException(PROBLEM_SETTING_JDO_DESC, e);
741         } catch (IllegalAccessException e) {
742             throw new BuildException(PROBLEM_SETTING_JDO_DESC, e);
743         } catch (InvocationTargetException e) {
744             throw new BuildException(PROBLEM_SETTING_JDO_DESC, e);
745         }
746     }
747 
748 
749 
750 }