KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > generator > XJCTask


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
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.apache.ws.jaxme.generator;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.net.URL JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import org.apache.ws.jaxme.generator.impl.GeneratorImpl;
30 import org.apache.ws.jaxme.generator.sg.SGFactoryChain;
31 import org.apache.ws.jaxme.generator.sg.SchemaSG;
32 import org.apache.ws.jaxme.generator.sg.impl.JAXBSchemaReader;
33 import org.apache.ws.jaxme.generator.sg.impl.JaxMeSchemaReader;
34 import org.apache.ws.jaxme.js.JavaSource;
35 import org.apache.ws.jaxme.js.JavaSourceFactory;
36 import org.apache.ws.jaxme.js.TextFile;
37 import org.apache.ws.jaxme.logging.AntProjectLoggerFactory;
38 import org.apache.ws.jaxme.logging.LoggerAccess;
39 import org.apache.ws.jaxme.logging.LoggerFactory;
40 import org.apache.ws.jaxme.util.ClassLoader;
41 import org.apache.ws.jaxme.xs.parser.impl.LocSAXException;
42 import org.apache.tools.ant.BuildException;
43 import org.apache.tools.ant.DirectoryScanner;
44 import org.apache.tools.ant.Project;
45 import org.apache.tools.ant.Task;
46 import org.apache.tools.ant.types.Commandline;
47 import org.apache.tools.ant.types.FileSet;
48 import org.apache.tools.ant.types.Path;
49 import org.xml.sax.SAXParseException JavaDoc;
50
51
52 /** <p>An Ant task for running JaxMe, designed to be JAXB compatible.</p>
53  * <p>This task supports the following attributes:</p>
54  * <table border="1">
55  * <tr>
56  * <th>Name</th>
57  * <th>Description</th>
58  * <th>Required/Default</th>
59  * </tr>
60  * <tr>
61  * <td>schema</td>
62  * <td>Name of a schema file being compiled</td>
63  * <td>This or nested &lt;schema&gt; elements are required</td>
64  * </tr>
65  * <tr>
66  * <td>binding</td>
67  * <td>An external binding file being applied to the schema file</td>
68  * <td>No</td>
69  * </tr>
70  * <tr>
71  * <td>force</td>
72  * <td>Setting this option to true forces the up-to-date check to fail.
73  * This option is mainly useful while working on the JaxMe generator.
74  * For JaxMe users, which only change schema files, this option isn't of much
75  * use. It is designed for JaxMe developers.</td>
76  * <td>No, false</td>
77  * </tr>
78  * <tr>
79  * <td>package</td>
80  * <td>Specifies the generated Java sources package name. Overrides package specifications in
81  * the schema bindings, if any.</td>
82  * <td>No, a package may be specified in the schema bindings.</td>
83  * </tr>
84  * <tr>
85  * <td>target</td>
86  * <td>Specifies the target directory, where generated sources are being created. A package
87  * structure will be created below that directory. For example, with target="src" and
88  * package="org.acme", you will have files being created in "src/org/acme".</td>
89  * <td>No, defaults to the current directory</td>
90  * </tr>
91  * <tr>
92  * <td>readonly</td>
93  * <td>Generated Java source files are in read-only mode, if true is specified</td>
94  * <td>No, defaults to false</td>
95  * </tr>
96  * <tr>
97  * <td>extension</td>
98  * <td>If set to true, the XJC binding compiler will run in the extension mode.
99  * Otherwise, it will run in the strict conformance mode.</td>
100  * <td>No, defaults to false</td>
101  * </tr>
102  * <tr>
103  * <td>stackSize</td>
104  * <td>Specify the thread stack size for the XJC binding compiler (J2SE SDK v1.4 or higher).
105  * The XJC binding compiler can fail to compile large schemas with StackOverflowError and,
106  * in that case, this option can be used to extend the stack size. If unspecified, the default
107  * VM size is used. The format is equivalent to the -Xss command-line argument for Sun Microsystems JVM.
108  * This value can be specified in bytes (stackSize="2097152"), kilobytes (stackSize="2048kb"),
109  * or megabytes (stackSize="2mb").<br>
110  * This attribute is ignored by the JaxMe ant task and present for compatibility reasons only.</td>
111  * <td>No, defaults to false</td>
112  * </tr>
113  * <tr>
114  * <td>removeOldOutput</td>
115  * <td>If one or more nested &lt;produces&gt; elements are specified and this attribute is
116  * set to true, then the Ant task will ensure that only generated files will remain. In other
117  * words, if you had removed an element named "Foo" from the previous schema version, then the
118  * Ant task will remove "Foo.java".</td>
119  * <td>No, defaults to false</td>
120  * </tr>
121  * <tr>
122  * <td>validating</td>
123  * <td>Sets whether the XML schema parser is validating. By default it isn't.</td>
124  * <td>No, defaults to false</td>
125  * </tr>
126  * </table>
127  * <p>Besides the attributes, the ant task also supports the following nested elements:</p>
128  * <table border="1">
129  * <tr>
130  * <th>Name</th>
131  * <th>Description</th>
132  * <th>Required/Multiplicity</th>
133  * </tr>
134  * <tr>
135  * <td>schema</td>
136  * <td>Multiple schema files may be compiled in one or more nested &lt;schema&gt;
137  * elements. The element syntax is equivalent to a nested &lt;fileset&gt;.
138  * Use of a nested &lt;schema&gt; element is mutually exclusive with the use
139  * of a "schema" attribute.</td>
140  * <td>0 - Unbounded</td>
141  * </tr>
142  * <tr>
143  * <td>binding</td>
144  * <td>Multiple external binding files may be specified. The element syntax is equivalent
145  * to a nested &lt;fileset&gt;. Use of a nested &lt;binding&gt; element is
146  * mutually exclusive with the use of a "binding" attribute.</td>
147  * <td>0 - Unbounded</td>
148  * </tr>
149  * <tr>
150  * <td>classpath</td>
151  * <td>This nested element is ignored by the JaxMe ant task and exists for compatibility
152  * to the JAXB ant task only. In the case of JAXB it specifies a classpath for loading
153  * user defined types (required in the case of a &lt;javaType&gt; customization)
154  * </td>
155  * <td>0 - Unbounded</td>
156  * </tr>
157  * <tr>
158  * <td>arg</td>
159  * <td>This nested element is ignored by the JaxMe ant task and exists for compatibility
160  * to the JAXB ant task only. In the case of JAXB it specifies additional command line
161  * arguments being passed to the XJC. For details about the syntax, see the relevant
162  * section in the Ant manual.<br>
163  * This nested element can be used to specify various options not natively supported in
164  * the xjc Ant task. For example, currently there is no native support for the following
165  * xjc command-line options:
166  * <ul>
167  * <li>-nv</li>
168  * <li>-catalog</li>
169  * <li>-use-runtime</li>
170  * <li>-schema</li>
171  * <li>-dtd</li>
172  * <li>-relaxng</li>
173  * </ul>
174  * </td>
175  * <td>0 - Unbounded</td>
176  * </tr>
177  * <tr>
178  * <td>dtd</td>
179  * <td>If this nested element is used to specify, that the input files
180  * aren't instances of XML Schema, but DTD's. The nested element may
181  * have an attribute "targetNamespace", which specifies an optional
182  * target namespace.
183  * </td>
184  * <td>No</td>
185  * </tr>
186  * <tr>
187  * <td>depends</td>
188  * <td>By default the JaxMe Ant tasks up-to-date check considers the specified schema
189  * and binding files only. This is insufficient, if other schema files are included,
190  * imported or redefined.<br>
191  * The nested &lt;depends&gt; element allows to specify additional files to consider
192  * for the up-to-date check. Typically these are the additional schema files.<br>
193  * Syntactically the &lt;depends&gt; element specifies a nested &lt;fileset&gt;.</td>
194  * <td>0 - Unbounded</td>
195  * </tr>
196  * <tr>
197  * <td>produces</td>
198  * <td>Specifies the set of files being created by the JaxMe ant task. These files are
199  * considered as targets for the up-to-date check. The syntax of the &lt;produces&gt;
200  * element is equivalent to a nested &lt;fileset&gt;. However, you typically do not
201  * need to set the "dir" attribute, because it defaults to the target directory.</td>
202  * <td>0 - Unbounded</td>
203  * </tr>
204  * <tr>
205  * <td>property</td>
206  * <td>Sets a property value. These properties may be used by the various source
207  * generators to configure the behaviour. For example, the JDBC schema reader uses
208  * the options "jdbc.driver", "jdbc.url", "jdbc.user", and "jdbc.password" to
209  * configure the database connection. Each property must have attributes "name" (the
210  * property name) and "value" (the property value).</td>
211  * <td>0 - Unbounded</td>
212  * </tr>
213  * <tr>
214  * <td>schemaReader</td>
215  * <td>Configures the schema reader to use. Defaults to
216  * "org.apache.ws.jaxme.generator.sg.impl.JAXBSchemaReader", which is the JAXB compliant
217  * schema reader. An alternative schema readers is, for example,
218  * "org.apache.ws.jaxme.generator.sg.impl.JaxMeSchemaReader" (a subclass of JAXBSchemaReader
219  * with JaxMe specific extensions).</td>
220  * <td>0 - 1</td>
221  * </tr>
222  * <tr>
223  * <td>sgFactoryChain</td>
224  * <td>If the schema reader is an instance of
225  * {@link org.apache.ws.jaxme.generator.sg.impl.JAXBSchemaReader}, then you may
226  * add instances of {@link org.apache.ws.jaxme.generator.sg.SGFactoryChain} to
227  * the schema generation process. For example, such chains are used to create
228  * the persistency layer. The best example is the
229  * {@link org.apache.ws.jaxme.pm.generator.jdbc.JaxMeJdbcSG}, which is able to
230  * populate the schema with tables and columns read from a database via
231  * JDBC metadata.</td>
232  * <td>0 - Unbounded</td>
233  * </tr>
234  * </table>
235  * <p>By default, the JaxMe ant task will always run the generator and create new files. This
236  * is typically inappropriate for an ant script where your desire is to have as little
237  * modifications as possible, because new files also need to be recompiled, which is slow
238  * and time consuming.</p>
239  * <p>To achieve a better behaviour, use the nested &lt;produces&gt; and &lt;depends&gt; elements.
240  * If one or more &lt;produces&gt; element is specified, then an up-to-date check is performed
241  * as follows:
242  * <ol>
243  * <li>If either of the filesets specified by the &lt;produces&gt; elements is empty,
244  * then the binding compiler will run.</li>
245  * <li>Otherwise the sets of source and target files will be created. The set of source
246  * files is specified by the "schema" and "binding" attributes, and by the nested
247  * &lt;schema&gt;, &lt;binding&gt;, and &lt;depends&gt; elements. If any of the files
248  * in the source set is newer than any of the files in the target set, then the
249  * binding comoiler will run.</li>
250  * </ol>
251  *
252  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
253  */

254 public class XJCTask extends Task {
255     /** This class is used to store the nested element "dtd".
256      */

257     public static class Dtd {
258         private String JavaDoc targetNamespace;
259         /** Sets the target namespace being used.
260          */

261         public void setTargetNamespace(String JavaDoc pTargetNamespace) {
262             targetNamespace = pTargetNamespace;
263         }
264         /** Returns the target namespace being used.
265          */

266         public String JavaDoc getTargetNamespace() {
267             return targetNamespace;
268         }
269     }
270
271   public static class Property {
272     private String JavaDoc name;
273     private String JavaDoc value;
274     public void setName(String JavaDoc pName) { name = pName; }
275     public void setValue(String JavaDoc pValue) { value = pValue; }
276     public String JavaDoc getName() { return name; }
277     public String JavaDoc getValue() { return value; }
278     public void finish() {
279       if (name == null) {
280         throw new NullPointerException JavaDoc("Missing attribute: 'name'");
281       }
282       if (value == null) {
283         throw new NullPointerException JavaDoc("Missing attribute: 'value'");
284       }
285     }
286   }
287
288   public static class ClassType {
289     private String JavaDoc className;
290     public void setClassName(String JavaDoc pClassName) {
291       className = pClassName;
292     }
293     public String JavaDoc getClassName() {
294       return className;
295     }
296     public Object JavaDoc getInstance(Class JavaDoc pInstanceClass) {
297       if (className == null) {
298         throw new NullPointerException JavaDoc("Missing attribute: 'class'");
299       }
300       Class JavaDoc cl;
301       try {
302         cl = ClassLoader.getClass(className, pInstanceClass);
303       } catch (ClassNotFoundException JavaDoc e) {
304         throw new BuildException("Could not load class " + className, e);
305       } catch (IllegalArgumentException JavaDoc e) {
306         throw new BuildException(e);
307       }
308
309       try {
310         return cl.newInstance();
311       } catch (Exception JavaDoc e) {
312         throw new BuildException("The class " + className +
313                                   " could not be instantiated: " +
314                                   e.getMessage(), e);
315       }
316     }
317   }
318
319   private File JavaDoc binding, schema, target;
320   private String JavaDoc packageName;
321   private boolean readOnly, extension, removeOldOutput, force, isValidating;
322   private boolean isSettingLoggerFactory = true;
323   private String JavaDoc stackSize;
324   private List JavaDoc bindings = new ArrayList JavaDoc(), schemas = new ArrayList JavaDoc();
325   private List JavaDoc depends = new ArrayList JavaDoc(), produces = new ArrayList JavaDoc();
326   private List JavaDoc sgFactoryChains = new ArrayList JavaDoc();
327   private ClassType schemaReader;
328   private List JavaDoc properties = new ArrayList JavaDoc();
329   private Dtd dtd;
330
331   /** <p>Sets a property value. These properties may be used by the various source
332    * generators to configure the behaviour. For example, the JDBC schema reader uses
333    * the options "jdbc.driver", "jdbc.url", "jdbc.user", and "jdbc.password" to
334    * configure the database connection. Each property must have attributes "name" (the
335    * property name) and "value" (the property value).</p>
336    */

337   public Property createProperty() {
338     Property property = new Property();
339     properties.add(property);
340     return property;
341   }
342
343   /** <p>Returns the configured property values. These properties may be used by the various source
344    * generators to configure the behaviour. For example, the JDBC schema reader uses
345    * the options "jdbc.driver", "jdbc.url", "jdbc.user", and "jdbc.password" to
346    * configure the database connection. Each property must have attributes "name" (the
347    * property name) and "value" (the property value).</p>
348    */

349   public Property[] getProperties() {
350     return (Property[]) properties.toArray(new Property[properties.size()]);
351   }
352
353   /** <p>Configures the schema reader to use. Defaults to
354    * "org.apache.ws.jaxme.generator.sg.impl.JAXBSchemaReader", which is the JAXB compliant
355    * schema reader. An alternative schema readers is, for example,
356    * "org.apache.ws.jaxme.generator.sg.impl.JaxMeSchemaReader" (a subclass of JAXBSchemaReader
357    * with JaxMe specific extensions).</p>
358    */

359   public ClassType createSchemaReader() {
360     if (schemaReader != null) {
361       throw new BuildException("Only one SchemaReader may be configured");
362     }
363     schemaReader = new ClassType();
364     return schemaReader;
365   }
366
367   /** <p>Returns the configured schema reader to use. Defaults to
368    * "org.apache.ws.jaxme.generator.sg.impl.JAXBSchemaReader", which is the JAXB compliant
369    * schema reader. An alternative schema readers is, for example,
370    * "org.apache.ws.jaxme.generator.sg.impl.JaxMeSchemaReader" (a subclass of JAXBSchemaReader
371    * with JaxMe specific extensions).</p>
372    */

373   public SchemaReader getSchemaReader() {
374     if (schemaReader == null) {
375       if (isExtension()) {
376         return new JaxMeSchemaReader();
377       } else {
378         return new JAXBSchemaReader();
379       }
380     } else {
381       return (SchemaReader) schemaReader.getInstance(SchemaReader.class);
382     }
383   }
384
385   /** <p>Configures a new instance of
386    * {@link org.apache.ws.jaxme.generator.sg.SGFactoryChain} being included into
387    * the schema generation process. This option is valid only, if the schema reader
388    * is an instance of {@link JAXBSchemaReader}, because its method
389    * {@link JAXBSchemaReader#addSGFactoryChain(Class)} must be invoked.</p>
390    * <p>The order of the chain elements may be significant. The schema reader
391    * itself will always be the last element in the chain.</p>
392    */

393   public ClassType createSGFactoryChain() {
394     ClassType result = new ClassType();
395     sgFactoryChains.add(result);
396     return result;
397   }
398
399   /** <p>Returns the array of configured instances of
400    * {@link org.apache.ws.jaxme.generator.sg.SGFactoryChain}. The order of
401    * the array is significant. The schema reader itself will always be the
402    * last element in the chain. Therefore, it is not present in the array.</p>
403    */

404   public ClassType[] getSGFactoryChains() {
405     return (ClassType[]) sgFactoryChains.toArray(new ClassType[sgFactoryChains.size()]);
406   }
407
408   /** <p>Returns the ant tasks description.</p>
409    */

410   public String JavaDoc getDescription() {
411     return "A JaxMe generator task converting XML schemata into Java source files.";
412   }
413
414   /** <p>Sets whether the XML schema parser is validating.</p>
415    */

416   public void setValidating(boolean pValidating) {
417     isValidating = pValidating;
418   }
419
420   /** <p>Returns whether the XML schema parser is validating.</p>
421    */

422   public boolean isValidating() {
423     return isValidating;
424   }
425
426
427   /** <p>Setting this option to true forces the up-to-date check to fail.
428    * This option is mainly useful while working on the JaxMe generator.
429    * For JaxMe users, which only change schema files, this option isn't of much
430    * use. It is designed for JaxMe developers.</p>
431    */

432   public boolean isForce() {
433     return force;
434   }
435
436   /** <p>Setting this option to true forces the up-to-date check to fail.
437    * This option is mainly useful while working on the JaxMe generator.
438    * For JaxMe users, which only change schema files, this option isn't of much
439    * use. It is designed for JaxMe developers.</p>
440    */

441   public void setForce(boolean pForce) {
442     force = pForce;
443   }
444
445   /** <p>Returns whether the ant task is setting the {@link LoggerFactory}. This
446    * option is only useful, if you are using the Ant task from another Java class
447    * and not from within Ant.</p>
448    */

449   public boolean isSettingLoggerFactory() {
450     return isSettingLoggerFactory;
451   }
452
453   /** <p>Sets whether the ant task is setting the {@link LoggerFactory}. This
454    * option is only useful, if you are using the Ant task from another Java class
455    * and not from within Ant.</p>
456    */

457   public void setSettingLoggerFactory(boolean pIsSettingLoggerFactory) {
458     isSettingLoggerFactory = pIsSettingLoggerFactory;
459   }
460
461   /** <p>Returns an external binding file being applied to the schema file.</p>
462    */

463   public File JavaDoc getBinding() {
464     return binding;
465   }
466
467   /** <p>Sets an external binding file being applied to the schema file.</p>
468    */

469   public void setBinding(File JavaDoc pBinding) {
470     binding = pBinding;
471   }
472
473   /** <p>Returns, whether the XJC binding compiler will run in the extension mode.
474    * By default, it will run in the strict conformance mode.</p>
475    */

476   public boolean isExtension() {
477     return extension;
478   }
479
480   /** <p>Sets, whether the XJC binding compiler will run in the extension mode.
481    * By default, it will run in the strict conformance mode.</p>
482    */

483   public void setExtension(boolean pExtension) {
484     extension = pExtension;
485   }
486
487   /** <p>Returns the generated Java sources package name. A non-null package specification
488    * overrides package specifications in the schema bindings, if any.</p>
489    */

490   public String JavaDoc getPackage() {
491     return packageName;
492   }
493
494   /** <p>Sets the generated Java sources package name. A non-null package specification
495    * overrides package specifications in the schema bindings, if any.</p>
496    */

497   public void setPackage(String JavaDoc pPackageName) {
498     packageName = pPackageName;
499   }
500
501   /** @deprecated Use {@link #setPackage(String)}.
502    */

503   public void setPackageName(String JavaDoc pPackageName) {
504       log("Warning: The 'packageName' attribute is updated to 'package', for compatibility reasons. Please update your build script.", Project.MSG_WARN);
505       setPackage(pPackageName);
506   }
507
508   /** <p>Returns, whether generated Java source files are in read-only mode.</p>
509    */

510   public boolean isReadOnly() {
511     return readOnly;
512   }
513
514   /** <p>Sets, whether generated Java source files are in read-only mode.</p>
515    */

516   public void setReadOnly(boolean pReadOnly) {
517     readOnly = pReadOnly;
518   }
519
520   /** <p>If one or more nested &lt;produces&gt; elements are specified and
521    * this attribute is set to true, then the Ant task will ensure that only
522    * generated files will remain. In other words, if you had removed an element
523    * named "Foo" from the previous schema version, then the Ant task will remove
524    * "Foo.java".</p>
525    */

526   public boolean isRemoveOldOutput() {
527     return removeOldOutput;
528   }
529
530   /** <p>If one or more nested &lt;produces&gt; elements are specified and
531    * this attribute is set to true, then the Ant task will ensure that only
532    * generated files will remain. In other words, if you had removed an element
533    * named "Foo" from the previous schema version, then the Ant task will remove
534    * "Foo.java".</p>
535    */

536   public void setRemoveOldOutput(boolean pRemoveOldOutput) {
537     removeOldOutput = pRemoveOldOutput;
538   }
539
540   /** <p>Returns the name of the schema file being compiled.</p>
541    */

542   public File JavaDoc getSchema() {
543     return schema;
544   }
545
546   /** <p>Sets the name of the schema file being compiled.</p>
547    */

548   public void setSchema(File JavaDoc pSchema) {
549     schema = pSchema;
550   }
551
552   /** <p>Returns the thread stack size for the XJC binding compiler (J2SE SDK v1.4 or higher).
553    * The XJC binding compiler can fail to compile large schemas with StackOverflowError and,
554    * in that case, this option can be used to extend the stack size. If unspecified, the default
555    * VM size is used. The format is equivalent to the -Xss command-line argument for Sun Microsystems JVM.
556    * This value can be specified in bytes (stackSize="2097152"), kilobytes (stackSize="2048kb"),
557    * or megabytes (stackSize="2mb").</p>
558    * <p>This attribute is ignored by the JaxMe ant task and present for compatibility reasons only.</p>
559    */

560   public String JavaDoc getStackSize() {
561     return stackSize;
562   }
563
564   /** <p>Sets the thread stack size for the XJC binding compiler (J2SE SDK v1.4 or higher).
565    * The XJC binding compiler can fail to compile large schemas with StackOverflowError and,
566    * in that case, this option can be used to extend the stack size. If unspecified, the default
567    * VM size is used. The format is equivalent to the -Xss command-line argument for Sun Microsystems JVM.
568    * This value can be specified in bytes (stackSize="2097152"), kilobytes (stackSize="2048kb"),
569    * or megabytes (stackSize="2mb").</p>
570    * <p>This attribute is ignored by the JaxMe ant task and present for compatibility reasons only.</p>
571    */

572   public void setStackSize(String JavaDoc pStackSize) {
573     stackSize = pStackSize;
574     log("The 'stackSize' attribute is ignored by the JaxMe ant task.", Project.MSG_WARN);
575   }
576
577   /** <p>Returns the target directory, where generated sources are being created. A package
578    * structure will be created below that directory. For example, with target="src" and
579    * package="org.acme", you will have files being created in "src/org/acme".</p>
580    */

581   public File JavaDoc getTarget() {
582     return target;
583   }
584
585   /** <p>Sets the target directory, where generated sources are being created. A package
586    * structure will be created below that directory. For example, with target="src" and
587    * package="org.acme", you will have files being created in "src/org/acme".</p>
588    */

589   public void setTarget(File JavaDoc pTarget) {
590     target = pTarget;
591   }
592
593   /** <p>Multiple schema files may be compiled in one or more nested &lt;schema&gt;
594    * elements. The element syntax is equivalent to a nested &lt;fileset&gt;.
595    * Use of a nested &lt;schema&gt; element is mutually exclusive with the use
596    * of a "schema" attribute.</p>
597    */

598   public void addSchema(FileSet pSchemas) {
599     if (getSchema() != null) {
600       throw new BuildException("The 'schema' attribute and the nested 'schema' element are mutually exclusive.");
601     }
602     schemas.add(pSchemas);
603   }
604
605   /** <p>Multiple schema files may be compiled in one or more nested &lt;schema&gt;
606    * elements. The element syntax is equivalent to a nested &lt;fileset&gt;.
607    * Use of a nested &lt;schema&gt; element is mutually exclusive with the use
608    * of a "schema" attribute.</p>
609    */

610   public FileSet[] getSchemas() {
611     return (FileSet[]) schemas.toArray(new FileSet[schemas.size()]);
612   }
613
614   /** <p>Multiple external binding files may be specified. The element syntax is equivalent
615    * to a nested &lt;fileset&gt;. Use of a nested &lt;binding&gt; element is
616    * mutually exclusive with the use of a "binding" attribute.</p>
617    */

618   public void addBinding(FileSet pBindings) {
619     if (getBinding() != null) {
620       throw new BuildException("The 'binding' attribute and the nested 'binding' element are mutually exclusive.");
621     }
622     bindings.add(pBindings);
623   }
624
625   /** <p>Multiple external binding files may be specified. The element syntax is equivalent
626    * to a nested &lt;fileset&gt;. Use of a nested &lt;binding&gt; element is
627    * mutually exclusive with the use of a "binding" attribute.</p>
628    */

629   public FileSet[] getBindings() {
630     return (FileSet[]) bindings.toArray(new FileSet[bindings.size()]);
631   }
632
633   /** <p>This nested element is ignored by the JaxMe ant task and exists for compatibility
634    * to the JAXB ant task only. In the case of JAXB it specifies a classpath for loading
635    * user defined types (required in the case of a &lt;javaType&gt; customization)</p>
636    */

637   public void addClasspath(Path pClasspath) {
638     log("The 'classpath' attribute is ignored by the JaxMe ant task.", Project.MSG_WARN);
639   }
640
641   /** <p>This nested element is ignored by the JaxMe ant task and exists for compatibility
642    * to the JAXB ant task only. In the case of JAXB it specifies additional command line
643    * arguments being passed to the XJC. For details about the syntax, see the relevant
644    * section in the Ant manual.<br>
645    * This nested element can be used to specify various options not natively supported in
646    * the xjc Ant task. For example, currently there is no native support for the following
647    * xjc command-line options:
648    * <ul>
649    * <li>-nv</li>
650    * <li>-catalog</li>
651    * <li>-use-runtime</li>
652    * <li>-schema</li>
653    * <li>-dtd</li>
654    * <li>-relaxng</li>
655    * </ul></p>
656    */

657   public void addArg(Commandline.Argument pArg) {
658     log("The 'arg' attribute is ignored by the JaxMe ant task.", Project.MSG_WARN);
659   }
660
661   /** <p>By default the JaxMe Ant tasks up-to-date check considers the specified schema
662    * and binding files only. This is insufficient, if other schema files are included,
663    * imported or redefined.<br>
664    * The nested &lt;depends&gt; element allows to specify additional files to consider
665    * for the up-to-date check. Typically these are the additional schema files.<br>
666    * Syntactically the &lt;depends&gt; element specifies a nested &lt;fileset&gt;.</p>
667    */

668   public void addDepends(FileSet pDepends) {
669     depends.add(pDepends);
670   }
671
672   /** <p>By default the JaxMe Ant tasks up-to-date check considers the specified schema
673    * and binding files only. This is insufficient, if other schema files are included,
674    * imported or redefined.<br>
675    * The nested &lt;depends&gt; element allows to specify additional files to consider
676    * for the up-to-date check. Typically these are the additional schema files.<br>
677    * Syntactically the &lt;depends&gt; element specifies a nested &lt;fileset&gt;.</p>
678    */

679   public FileSet[] getDepends() {
680     return (FileSet[]) depends.toArray(new FileSet[depends.size()]);
681   }
682
683   /** <p>Specifies the set of files being created by the JaxMe ant task. These files are
684    * considered as targets for the up-to-date check. The syntax of the &lt;produces&gt;
685    * element is equivalent to a nested &lt;fileset&gt;.</p>
686    */

687   public FileSet createProduces() {
688     FileSet result = new FileSet();
689     produces.add(result);
690     return result;
691   }
692
693   /** <p>Returns the set of files being created by the JaxMe ant task. These files are
694    * considered as targets for the up-to-date check. The syntax of the &lt;produces&gt;
695    * element is equivalent to a nested &lt;fileset&gt;.</p>
696    */

697   public FileSet[] getProduces() {
698     return (FileSet[]) produces.toArray(new FileSet[produces.size()]);
699   }
700
701     /** Creates a nested element "dtd".
702      */

703     public Dtd createDtd() {
704         if (dtd == null) {
705             dtd = new Dtd();
706             return dtd;
707         } else {
708             throw new BuildException("Multiple nested 'dtd' elements are forbidden.",
709                                      getLocation());
710         }
711     }
712
713     /** Returns the nested element "dtd".
714      */

715     public Dtd getDtd() {
716         return dtd;
717     }
718
719   public void finish() {
720     if (getSchema() == null && getSchemas().length == 0) {
721       throw new BuildException("Either of the 'schema' attribute or the nested 'schema' elements must be given.",
722                                 getLocation());
723     }
724   }
725
726   private File JavaDoc[] getFiles(FileSet[] pFileSets) {
727     List JavaDoc list = new ArrayList JavaDoc();
728     for (int i = 0; i < pFileSets.length; i++) {
729       FileSet fileSet = pFileSets[i];
730       DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());
731       scanner.scan();
732       String JavaDoc[] files = scanner.getIncludedFiles();
733       for (int j = 0; j < files.length; j++) {
734         list.add(new File JavaDoc(fileSet.getDir(getProject()), files[j]));
735       }
736     }
737     return (File JavaDoc[]) list.toArray(new File JavaDoc[list.size()]);
738   }
739
740   private File JavaDoc[] getSchemaFiles() {
741     if (getSchema() != null) {
742       return new File JavaDoc[]{getSchema()};
743     } else {
744       return getFiles(getSchemas());
745     }
746   }
747
748   private File JavaDoc[] getBindingFiles() {
749     if (getBinding() != null) {
750       return new File JavaDoc[]{getBinding()};
751     } else {
752       return getFiles(getBindings());
753     }
754   }
755
756   private File JavaDoc[] getDependsFiles() {
757     return getFiles(getDepends());
758   }
759
760   public boolean isUpToDate(File JavaDoc[] pSchemaFiles, File JavaDoc[] pBindingFiles, File JavaDoc[] pDependsFiles, List JavaDoc pProducesList) {
761     FileSet[] myProduces = getProduces();
762     if (myProduces.length == 0) {
763       log("No nested 'produces' elements, up-to-date check returns false", Project.MSG_VERBOSE);
764       return false;
765     }
766
767     boolean result = true;
768     long firstTarget = 0;
769     File JavaDoc firstTargetFile = null;
770     for (int i = 0; i < myProduces.length; i++) {
771       File JavaDoc dir = myProduces[i].getDir(getProject());
772       if (dir == null) {
773         dir = getTarget();
774         if (dir == null) {
775           dir = getProject().getBaseDir();
776         }
777         myProduces[i].setDir(dir);
778       }
779       if (!dir.exists()) {
780         log("The directory specified by the nested 'produces' element #" + i + " does not exist, up-to-date check returns false",
781             Project.MSG_VERBOSE);
782         result = false;
783         continue;
784       }
785       DirectoryScanner scanner = myProduces[i].getDirectoryScanner(getProject());
786       scanner.scan();
787       String JavaDoc[] files = scanner.getIncludedFiles();
788       if (files.length == 0) {
789         log("The fileset specified by the nested 'produces' element #" + i + " is empty, up-to-date check returns false",
790             Project.MSG_VERBOSE);
791         result = false;
792       }
793       for (int j = 0; j < files.length; j++) {
794         File JavaDoc f = new File JavaDoc(dir, files[j]).getAbsoluteFile();
795         if (pProducesList != null) {
796           pProducesList.add(f);
797         }
798         long l = f.lastModified();
799         if (l == -1) {
800           log("Unable to determine timestamp of target file " + f + ", up-to-date check returns false.", Project.MSG_VERBOSE);
801           result = false;
802         }
803         if (firstTargetFile == null || firstTarget > l) {
804           firstTargetFile = f;
805           firstTarget = l;
806         }
807       }
808     }
809
810     if (isForce()) {
811       log("Force option is set, up-to-date check returns false", Project.MSG_VERBOSE);
812       result = false;
813     }
814
815     if (!result) {
816       return false;
817     }
818
819     List JavaDoc sourceFiles = new ArrayList JavaDoc();
820     for (int i = 0; i < pSchemaFiles.length; i++) {
821       sourceFiles.add(pSchemaFiles[i]);
822     }
823     for (int i = 0; i < pBindingFiles.length; i++) {
824       sourceFiles.add(pBindingFiles[i]);
825     }
826     for (int i = 0; i < pDependsFiles.length; i++) {
827       sourceFiles.add(pDependsFiles[i]);
828     }
829
830     long lastSource = 0;
831     File JavaDoc lastSourceFile = null;
832     for (Iterator JavaDoc iter = sourceFiles.iterator(); iter.hasNext(); ) {
833       File JavaDoc f = (File JavaDoc) iter.next();
834       long l = f.lastModified();
835       if (l == -1) {
836         log("Unable to determine timestamp of source file " + f + ", up-to-date check returns false.", Project.MSG_VERBOSE);
837         result = false;
838       }
839       if (lastSourceFile == null || lastSource < l) {
840         lastSource = l;
841         lastSourceFile = f;
842       }
843     }
844
845     if (lastSourceFile == null) {
846       log("No source files found, up-to-date check returns false.", Project.MSG_VERBOSE);
847       return false;
848     }
849
850     if (!result) {
851       return false;
852     }
853
854     try {
855       URL JavaDoc url = Generator.class.getClassLoader().getResource(Generator.class.getName().replace('.', '/') + ".class");
856       if (url != null) {
857         long l = url.openConnection().getLastModified();
858         if (l != 0 && lastSource < l) {
859           log("Generator class is newer than any schema files, using Generator classes timestamp as schema timestamp.", Project.MSG_DEBUG);
860           lastSource = l;
861         }
862       }
863     } catch (IOException JavaDoc e) {
864     }
865
866     if (lastSource >= firstTarget) {
867       log("Source file " + lastSourceFile + " is more recent than target file " + firstTargetFile + ", up-to-date check returns false", Project.MSG_VERBOSE);
868       return false;
869     }
870
871     log("All target files are up-to-date.", Project.MSG_VERBOSE);
872     return true;
873   }
874
875   public class MyClassLoader extends java.lang.ClassLoader JavaDoc {
876     private java.lang.ClassLoader JavaDoc parent;
877     public java.lang.ClassLoader JavaDoc getMyParent() {
878       return parent;
879     }
880     public MyClassLoader(java.lang.ClassLoader JavaDoc pParent) {
881       super(XJCTask.this.getClass().getClassLoader());
882       parent = pParent;
883     }
884     public Class JavaDoc findClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
885       return parent.loadClass(name);
886     }
887     public URL JavaDoc findResource(String JavaDoc resource) {
888       return parent.getResource(resource);
889     }
890     public Enumeration JavaDoc findResources(String JavaDoc resource) throws IOException JavaDoc {
891       return parent.getResources(resource);
892     }
893   }
894
895   public void stopLogging(LoggerFactory pFactory) {
896     if (pFactory != null) {
897       LoggerAccess.setLoggerFactory(pFactory);
898     }
899   }
900
901   public LoggerFactory initLogging() {
902     if (!isSettingLoggerFactory()) {
903       return null;
904     }
905     LoggerFactory loggerFactory = LoggerAccess.getLoggerFactory();
906     if (!(loggerFactory instanceof AntProjectLoggerFactory)) {
907       loggerFactory = new AntProjectLoggerFactory(this);
908       LoggerAccess.setLoggerFactory(loggerFactory);
909       return loggerFactory;
910     }
911     return null;
912   }
913
914   public void execute() {
915     java.lang.ClassLoader JavaDoc parent = Thread.currentThread().getContextClassLoader();
916     MyClassLoader cl = new MyClassLoader(parent == null ? getClass().getClassLoader() : parent);
917     LoggerFactory loggerFactory = initLogging();
918     try {
919       Thread.currentThread().setContextClassLoader(cl);
920
921       File JavaDoc[] schemaFiles = getSchemaFiles();
922       if (schemaFiles.length == 0) {
923         log("No schema files specified", Project.MSG_WARN);
924         return;
925       }
926   
927       File JavaDoc[] bindingFiles = getBindingFiles();
928       if (bindingFiles.length > 0) {
929         throw new BuildException("External schema bindings are still unsupported by JaxMe.", getLocation());
930       }
931   
932       File JavaDoc[] dependFiles = getDependsFiles();
933       List JavaDoc producesFiles = isRemoveOldOutput() ? new ArrayList JavaDoc() : null;
934       if (isUpToDate(schemaFiles, bindingFiles, dependFiles, producesFiles)) {
935         return;
936       }
937   
938       Set JavaDoc producesFilesSet = null;
939       if (producesFiles != null) {
940         producesFilesSet = new HashSet JavaDoc();
941         for (Iterator JavaDoc iter = producesFiles.iterator(); iter.hasNext(); ) {
942           File JavaDoc f = ((File JavaDoc) iter.next());
943           producesFilesSet.add(f);
944         }
945       }
946       
947   
948       Generator generator = new GeneratorImpl();
949       generator.setForcingOverwrite(isForce());
950       generator.setSettingReadOnly(isReadOnly());
951       generator.setValidating(isValidating());
952       if (getPackage() != null) {
953         generator.setProperty("jaxme.package.name", getPackage());
954       }
955       Dtd myDtd = getDtd();
956       if (myDtd != null) {
957         generator.setProperty("jaxme.dtd.input", "true");
958         if (myDtd.getTargetNamespace() != null) {
959           generator.setProperty("jaxme.dtd.targetNamespace", myDtd.getTargetNamespace());
960         }
961       }
962       Property[] myProperties = getProperties();
963       for (int i = 0; i < myProperties.length; i++) {
964         Property ot = myProperties[i];
965         log("Option " + ot.getName() + "=" + ot.getValue(), Project.MSG_VERBOSE);
966         generator.setProperty(ot.getName(), ot.getValue());
967       }
968
969       SchemaReader reader = getSchemaReader();
970       if (reader instanceof JAXBSchemaReader) {
971         ((JAXBSchemaReader) reader).setSupportingExtensions(isExtension());
972       }
973       generator.setSchemaReader(reader);
974       reader.setGenerator(generator);
975       generator.setTargetDirectory(getTarget());
976
977       ClassType[] mySgFactoryChains = getSGFactoryChains();
978       if (mySgFactoryChains.length > 0) {
979         if (!(reader instanceof JAXBSchemaReader)) {
980           throw new BuildException("The nested child element 'sgFactoryChain' is valid only, if the schema reader is an instance of "
981                                     + JAXBSchemaReader.class.getName(), getLocation());
982         }
983         for (int i = 0; i < mySgFactoryChains.length; i++) {
984           ClassType ct = mySgFactoryChains[i];
985           Class JavaDoc c;
986           try {
987             c = cl.loadClass(ct.getClassName());
988           } catch (ClassNotFoundException JavaDoc e) {
989             throw new BuildException("Failed to load SGFactoryChain implementation class " + ct.getClassName(),
990                                       getLocation());
991           }
992           if (!SGFactoryChain.class.isAssignableFrom(c)) {
993             throw new BuildException("The SGFactoryChain class " + c.getName() +
994                                       " is not implementing " + SGFactoryChain.class.getName(),
995                                       getLocation());
996           }
997           reader.addSGFactoryChain(c);
998         }
999       }
1000
1001      for (int i = 0; i < schemaFiles.length; i++) {
1002        log("Reading schema file " + schemaFiles[i], Project.MSG_VERBOSE);
1003        try {
1004          SchemaSG schemaSG = generator.generate(schemaFiles[i]);
1005          if (producesFilesSet != null) {
1006            JavaSourceFactory jsf = schemaSG.getJavaSourceFactory();
1007            File JavaDoc targetDirectory = getTarget();
1008            for (Iterator JavaDoc iter = jsf.getJavaSources(); iter.hasNext(); ) {
1009              JavaSource js = (JavaSource) iter.next();
1010              File JavaDoc f = jsf.getLocation(targetDirectory, js).getAbsoluteFile();
1011              producesFilesSet.remove(f);
1012            }
1013            for (Iterator JavaDoc iter = jsf.getTextFiles(); iter.hasNext(); ) {
1014              TextFile tf = (TextFile) iter.next();
1015              File JavaDoc f = jsf.getLocation(targetDirectory, tf).getAbsoluteFile();
1016              producesFilesSet.remove(f);
1017            }
1018          }
1019        } catch (SAXParseException JavaDoc e) {
1020            String JavaDoc msg = LocSAXException.formatMsg(e.getMessage() == null ? e.getClass().getName() : e.getMessage(),
1021                                                   e.getPublicId(),
1022                                                   e.getSystemId(),
1023                                                   e.getLineNumber(),
1024                                                   e.getColumnNumber());
1025            throw new BuildException(msg, e, getLocation());
1026        } catch (Exception JavaDoc e) {
1027            String JavaDoc msg = e.getMessage();
1028            if (msg == null) {
1029                msg = e.getClass().getName();
1030            }
1031            throw new BuildException(schemaFiles[i] + ": " + msg, e, getLocation());
1032        }
1033      }
1034  
1035      if (producesFilesSet != null) {
1036        for (Iterator JavaDoc iter = producesFilesSet.iterator(); iter.hasNext(); ) {
1037          File JavaDoc f = (File JavaDoc) iter.next();
1038          log("Removing orphan file " + f, Project.MSG_VERBOSE);
1039          if (!f.delete()) {
1040            throw new BuildException("Unable to delete file " + f);
1041          }
1042        }
1043      }
1044    } finally {
1045      Thread.currentThread().setContextClassLoader(parent);
1046      stopLogging(loggerFactory);
1047    }
1048  }
1049}
1050
Popular Tags