View Javadoc
1   /*
2    * Copyright 2007 Werner Guttmann
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package org.castor.anttask;
15  
16  import java.io.File;
17  import java.io.FileWriter;
18  import java.io.IOException;
19  import java.util.Vector;
20  
21  import org.apache.tools.ant.BuildException;
22  import org.apache.tools.ant.DirectoryScanner;
23  import org.apache.tools.ant.taskdefs.MatchingTask;
24  import org.apache.tools.ant.types.FileSet;
25  import org.exolab.castor.xml.schema.Schema;
26  import org.exolab.castor.xml.schema.util.XMLInstance2Schema;
27  import org.xml.sax.SAXException;
28  
29  /**
30   * An <a href="http://ant.apache.org/">Ant</a> task to call the Castor {@link XMLInstance2Schema}
31   * tool. It can be passed a file, a directory, a Fileset or all three.
32   *
33   * @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner Guttmann</a>
34   * @version $Revision: 6543 $ $Date: 2005-03-05 06:42:06 -0700 (Sat, 05 Mar 2005) $
35   */
36  public final class XMLInstance2SchemaTask extends MatchingTask {
37  
38    /**
39     * Error message -- no input provided.
40     */
41    private static final String NO_XML_DOCUMENT_MSG =
42        "At least one XML document instance must be provided.";
43  
44    /**
45     * Enlists the XML file to process.
46     */
47    private File _xmlInstanceFile;
48  
49    /**
50     * Enlists a directory, for which the user wants to process all XML instance files.
51     **/
52    private File _xmlInstanceDir;
53  
54    /**
55     * Enlists the fileset the user wants to process.
56     */
57    private final Vector<FileSet> _xmlInstanceFileSets = new Vector<>();
58  
59    // Begin application-specific parameters
60  
61    /**
62     * Name of the XML schema file to which the output should be written.
63     */
64    private String _xmlSchemaFileName;
65  
66    /**
67     * Default grouping to be <xsd:ALL/>.
68     */
69    private boolean _defaultGroupingAsAll;
70  
71    /**
72     * Sets the individual schema that will have code generated for it.
73     * 
74     * @param file One schema file.
75     */
76    public void setFile(final File file) {
77      _xmlInstanceFile = file;
78    }
79  
80    /**
81     * Sets the directory such that all schemas in this directory will have code generated for them.
82     * 
83     * @param dir The directory containing schemas to process.
84     */
85    public void setDir(final File dir) {
86      _xmlInstanceDir = dir;
87    }
88  
89    /**
90     * Adds a fileset to process that contains schemas to process.
91     * 
92     * @param set An individual file set containing schemas.
93     */
94    public void addFileset(final FileSet set) {
95      _xmlInstanceFileSets.add(set);
96    }
97  
98    /**
99     * Specifies the name of the DDL file to be generated.
100    * 
101    * @param ddlFileName Name of the DDL file to be generated
102    */
103   public void setXmlSchemaFileName(final String ddlFileName) {
104     _xmlSchemaFileName = ddlFileName;
105   }
106 
107   /**
108    * Specifies the default grouping to be <xsd:all/>.
109    * 
110    * @param defaultGroupingAsAll Default grouping to be used
111    */
112   public void setDefaultGrouping(final String defaultGroupingAsAll) {
113     _defaultGroupingAsAll = true;
114   }
115 
116   /**
117    * Configured the code generator. If anything goes wrong during configuration of the Ant task a
118    * BuildException will be thrown.
119    */
120   private void config() {}
121 
122   /**
123    * Runs source generation. If anything goes wrong during source generation a BuildException will
124    * be thrown.
125    * 
126    * @param filePath an individual Schema to generate code for.
127    * @param outputFilePath Name of the output file to create.
128    */
129   private void processFile(final String filePath, final String outputFilePath) {
130     log("Processing " + filePath);
131     try {
132       XMLInstance2Schema schemaGenerator = new XMLInstance2Schema();
133       if (_defaultGroupingAsAll) {
134         schemaGenerator.setDefaultGroupingAsAll();
135       }
136       Schema schema = schemaGenerator.createSchema(filePath);
137       String outputFileName = outputFilePath;
138       if (outputFileName == null) {
139         outputFileName = deriveOutputFilePath(filePath);
140       }
141       FileWriter dstWriter = new FileWriter(outputFileName);
142       schemaGenerator.serializeSchema(dstWriter, schema);
143     } catch (IOException e) {
144       throw new BuildException(
145           "Problem writing to the given putput sink " + _xmlInstanceFile.getAbsolutePath(), e);
146     } catch (SAXException e) {
147       throw new BuildException(
148           "Problem streaming the generated XML schema instance " + "to the given file.", e);
149     }
150   }
151 
152   /**
153    * Derives the XML schema file name from the XML instance document name.
154    * 
155    * @param outputFileName Name of the XML instance document.
156    * @return The name of the XML schema instance.
157    */
158   private String deriveOutputFilePath(final String outputFileName) {
159     return outputFileName + ".xsd";
160   }
161 
162   /**
163    * Public execute method -- entry point for the Ant task. Loops over all schema that need code
164    * generated and creates needed code generators, then executes them. If anything goes wrong during
165    * execution of the Ant task a BuildException will be thrown.
166    * 
167    * @see org.apache.tools.ant.Task#execute()
168    */
169   public void execute() {
170     // Must have something to run the source generator on
171     if (_xmlInstanceFile == null && _xmlInstanceDir == null && _xmlInstanceFileSets.isEmpty()) {
172       throw new BuildException(NO_XML_DOCUMENT_MSG);
173     }
174 
175     config();
176 
177     // process just the file specified
178     if (_xmlInstanceFile != null) {
179       processFile(_xmlInstanceFile.getAbsolutePath(), _xmlSchemaFileName);
180     }
181 
182     // process all files in the given directory
183     if (_xmlInstanceDir != null && _xmlInstanceDir.exists() && _xmlInstanceDir.isDirectory()) {
184       log("Given XML schema file name will be ignored.");
185       DirectoryScanner ds = this.getDirectoryScanner(_xmlInstanceDir);
186 
187       String[] files = ds.getIncludedFiles();
188       for (String file : files) {
189         String filePath = _xmlInstanceDir.getAbsolutePath() + File.separator + file;
190         processFile(filePath, null);
191       }
192     }
193 
194     // process all files of the given FileSet
195     for (FileSet xmlInstanceFileSet : _xmlInstanceFileSets) {
196       log("Given XML schema file name will be ignored.");
197       FileSet fs = xmlInstanceFileSet;
198       DirectoryScanner ds = fs.getDirectoryScanner(getProject());
199       File subdir = fs.getDir(getProject());
200 
201       String[] files = ds.getIncludedFiles();
202       for (String file : files) {
203         String filePath = subdir.getAbsolutePath() + File.separator + file;
204         processFile(filePath, null);
205       }
206     }
207   }
208 }