1 package org.apache.torque.task;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.File;
20
21 import java.util.ArrayList;
22 import java.util.Hashtable;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.commons.lang.StringUtils;
27
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.DirectoryScanner;
30 import org.apache.tools.ant.types.FileSet;
31
32 import org.apache.torque.engine.EngineException;
33 import org.apache.torque.engine.database.model.AppData;
34 import org.apache.torque.engine.database.model.Database;
35 import org.apache.torque.engine.database.transform.XmlToAppData;
36
37 import org.apache.velocity.VelocityContext;
38 import org.apache.velocity.context.Context;
39 import org.apache.velocity.texen.ant.TexenTask;
40
41 /***
42 * A base torque task that uses either a single XML schema
43 * representing a data model, or a <fileset> of XML schemas.
44 * We are making the assumption that an XML schema representing
45 * a data model contains tables for a <strong>single</strong>
46 * database.
47 *
48 * @author <a href="mailto:jvanzyl@zenplex.com">Jason van Zyl</a>
49 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
50 * @version $Id: TorqueDataModelTask.java,v 1.2.2.2 2004/05/20 04:35:14 seade Exp $
51 */
52 public class TorqueDataModelTask extends TexenTask
53 {
54 /***
55 * XML that describes the database model, this is transformed
56 * into the application model object.
57 */
58 protected String xmlFile;
59
60 /***
61 * Fileset of XML schemas which represent our data models.
62 */
63 protected List filesets = new ArrayList();
64
65 /***
66 * Data models that we collect. One from each XML schema file.
67 */
68 protected List dataModels = new ArrayList();
69
70 /***
71 * Velocity context which exposes our objects
72 * in the templates.
73 */
74 protected Context context;
75
76 /***
77 * Map of data model name to database name.
78 * Should probably stick to the convention
79 * of them being the same but I know right now
80 * in a lot of cases they won't be.
81 */
82 protected Hashtable dataModelDbMap;
83
84 /***
85 * Hashtable containing the names of all the databases
86 * in our collection of schemas.
87 */
88 protected Hashtable databaseNames;
89
90
91
92
93
94
95 /***
96 * Name of the properties file that maps an SQL file
97 * to a particular database.
98 */
99 protected String sqldbmap;
100
101 /***
102 * The path to properties file containing db idiosyncrasies is
103 * constructed by appending the "getTargetDatabase()/db.props
104 * to this path.
105 */
106 private String basePathToDbProps;
107
108 /***
109 * The target database(s) we are generating SQL
110 * for. Right now we can only deal with a single
111 * target, but we will support multiple targets
112 * soon.
113 */
114 private String targetDatabase;
115
116 /***
117 * Target Java package to place the generated files in.
118 */
119 private String targetPackage;
120
121
122 /***
123 * Set the sqldbmap.
124 *
125 * @param sqldbmap th db map
126 */
127 public void setSqlDbMap(String sqldbmap)
128 {
129
130 this.sqldbmap = project.resolveFile(sqldbmap).toString();
131 }
132
133 /***
134 * Get the sqldbmap.
135 *
136 * @return String sqldbmap.
137 */
138 public String getSqlDbMap()
139 {
140 return sqldbmap;
141 }
142
143 /***
144 * Return the data models that have been
145 * processed.
146 *
147 * @return List data models
148 */
149 public List getDataModels()
150 {
151 return dataModels;
152 }
153
154 /***
155 * Return the data model to database name map.
156 *
157 * @return Hashtable data model name to database name map.
158 */
159 public Hashtable getDataModelDbMap()
160 {
161 return dataModelDbMap;
162 }
163
164 /***
165 * Get the xml schema describing the application model.
166 *
167 * @return String xml schema file.
168 */
169 public String getXmlFile()
170 {
171 return xmlFile;
172 }
173
174 /***
175 * Set the xml schema describing the application model.
176 *
177 * @param xmlFile The new XmlFile value
178 */
179 public void setXmlFile(String xmlFile)
180 {
181 this.xmlFile = project.resolveFile(xmlFile).toString();
182 }
183
184 /***
185 * Adds a set of xml schema files (nested fileset attribute).
186 *
187 * @param set a Set of xml schema files
188 */
189 public void addFileset(FileSet set)
190 {
191 filesets.add(set);
192 }
193
194 /***
195 * Get the current target database.
196 *
197 * @return String target database(s)
198 */
199 public String getTargetDatabase()
200 {
201 return targetDatabase;
202 }
203
204 /***
205 * Set the current target database. (e.g. mysql, oracle, ..)
206 *
207 * @param v target database(s)
208 */
209 public void setTargetDatabase(String v)
210 {
211 targetDatabase = v;
212 }
213
214 /***
215 * Get the current target package.
216 *
217 * @return return target java package.
218 */
219 public String getTargetPackage()
220 {
221 return targetPackage;
222 }
223
224 /***
225 * Set the current target package. This is where generated java classes will
226 * live.
227 *
228 * @param v target java package.
229 */
230 public void setTargetPackage(String v)
231 {
232 targetPackage = v;
233 }
234
235 /***
236 * The path to properties file containing db idiosyncrasies is
237 * constructed by appending the "getTargetDatabase()/db.props to this path.
238 *
239 * @return basepath to db.props
240 */
241 public String getBasePathToDbProps()
242 {
243 return basePathToDbProps;
244 }
245
246 /***
247 * The path to properties file containing db idiosyncrasies is
248 * constructed by appending the "getTargetDatabase()/db.props
249 * to this path.
250 *
251 * @param v basepath to db.props
252 */
253 public void setBasePathToDbProps(String v)
254 {
255 this.basePathToDbProps = v;
256 }
257
258 /***
259 * Set up the initial context for generating the SQL from the XML schema.
260 *
261 * @return the context
262 * @throws Exception
263 */
264 public Context initControlContext() throws Exception
265 {
266 XmlToAppData xmlParser;
267
268 if (xmlFile == null && filesets.isEmpty())
269 {
270 throw new BuildException("You must specify an XML schema or "
271 + "fileset of XML schemas!");
272 }
273
274 try
275 {
276 if (xmlFile != null)
277 {
278
279
280 xmlParser = new XmlToAppData(getTargetDatabase(),
281 getTargetPackage(), getBasePathToDbProps());
282 AppData ad = xmlParser.parseFile(xmlFile);
283 ad.setName(grokName(xmlFile));
284 dataModels.add(ad);
285 }
286 else
287 {
288
289 for (int i = 0; i < filesets.size(); i++)
290 {
291 FileSet fs = (FileSet) filesets.get(i);
292 DirectoryScanner ds = fs.getDirectoryScanner(project);
293 File srcDir = fs.getDir(project);
294
295 String[] dataModelFiles = ds.getIncludedFiles();
296
297
298 for (int j = 0; j < dataModelFiles.length; j++)
299 {
300 File f = new File(srcDir, dataModelFiles[j]);
301 xmlParser = new XmlToAppData(getTargetDatabase(),
302 getTargetPackage(),
303 getBasePathToDbProps());
304 AppData ad = xmlParser.parseFile(f.toString());
305 ad.setName(grokName(f.toString()));
306 dataModels.add(ad);
307 }
308 }
309 }
310
311 Iterator i = dataModels.iterator();
312 databaseNames = new Hashtable();
313 dataModelDbMap = new Hashtable();
314
315
316
317 while (i.hasNext())
318 {
319 AppData ad = (AppData) i.next();
320 Database database = ad.getDatabase();
321 databaseNames.put(database.getName(), database.getName());
322 dataModelDbMap.put(ad.getName(), database.getName());
323 }
324 }
325 catch (EngineException ee)
326 {
327 throw new BuildException(ee);
328 }
329
330 context = new VelocityContext();
331
332
333
334 context.put("dataModels", dataModels);
335 context.put("databaseNames", databaseNames);
336 context.put("targetDatabase", targetDatabase);
337 context.put("targetPackage", targetPackage);
338
339 return context;
340 }
341
342 /***
343 * Gets a name to use for the application's data model.
344 *
345 * @param xmlFile The path to the XML file housing the data model.
346 * @return The name to use for the <code>AppData</code>.
347 */
348 private String grokName(String xmlFile)
349 {
350
351
352
353
354 String name = "data-model";
355 int i = xmlFile.lastIndexOf(System.getProperty("file.separator"));
356 if (i != -1)
357 {
358
359 i++;
360
361 int j = xmlFile.lastIndexOf('.');
362 if (i < j)
363 {
364 name = xmlFile.substring(i, j);
365 }
366 else
367 {
368
369 name = xmlFile.substring(i);
370 }
371 }
372 return name;
373 }
374
375 /***
376 * Override Texen's context properties to map the
377 * torque.xxx properties (including defaults set by the
378 * org/apache/torque/defaults.properties) to just xxx.
379 *
380 * <p>
381 * Also, move xxx.yyy properties to xxxYyy as Velocity
382 * doesn't like the xxx.yyy syntax.
383 * </p>
384 *
385 * @param file the file to read the properties from
386 */
387 public void setContextProperties(String file)
388 {
389 super.setContextProperties(file);
390
391
392 Hashtable env = super.getProject().getProperties();
393 for (Iterator i = env.keySet().iterator(); i.hasNext();)
394 {
395 String key = (String) i.next();
396 if (key.startsWith("torque."))
397 {
398 String newKey = key.substring("torque.".length());
399 int j = newKey.indexOf(".");
400 while (j != -1)
401 {
402 newKey =
403 newKey.substring(0, j)
404 + StringUtils.capitalise(newKey.substring(j + 1));
405 j = newKey.indexOf(".");
406 }
407
408 contextProperties.setProperty(newKey, env.get(key));
409 }
410 }
411 }
412 }