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