Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
TorqueDataModelTask |
|
| 1.7619047619047619;1.762 |
1 | package org.apache.torque.task; | |
2 | ||
3 | /* | |
4 | * Licensed to the Apache Software Foundation (ASF) under one | |
5 | * or more contributor license agreements. See the NOTICE file | |
6 | * distributed with this work for additional information | |
7 | * regarding copyright ownership. The ASF licenses this file | |
8 | * to you under the Apache License, Version 2.0 (the | |
9 | * "License"); you may not use this file except in compliance | |
10 | * with the License. You may obtain a copy of the License at | |
11 | * | |
12 | * http://www.apache.org/licenses/LICENSE-2.0 | |
13 | * | |
14 | * Unless required by applicable law or agreed to in writing, | |
15 | * software distributed under the License is distributed on an | |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
17 | * KIND, either express or implied. See the License for the | |
18 | * specific language governing permissions and limitations | |
19 | * under the License. | |
20 | */ | |
21 | ||
22 | import java.io.File; | |
23 | import java.util.ArrayList; | |
24 | import java.util.Date; | |
25 | import java.util.Hashtable; | |
26 | import java.util.Iterator; | |
27 | import java.util.List; | |
28 | import java.util.Map; | |
29 | ||
30 | import org.apache.commons.lang.StringUtils; | |
31 | import org.apache.tools.ant.BuildException; | |
32 | import org.apache.tools.ant.DirectoryScanner; | |
33 | import org.apache.tools.ant.types.FileSet; | |
34 | import org.apache.torque.engine.EngineException; | |
35 | import org.apache.torque.engine.database.model.Database; | |
36 | import org.apache.velocity.VelocityContext; | |
37 | import org.apache.velocity.context.Context; | |
38 | import org.apache.texen.ant.TexenTask; | |
39 | import org.kuali.core.db.torque.DatabaseParser; | |
40 | import org.kuali.core.db.torque.KualiXmlToAppData; | |
41 | ||
42 | /** | |
43 | * A base torque task that uses either a single XML schema representing a data model, or a <fileset> of XML | |
44 | * schemas. We are making the assumption that an XML schema representing a data model contains tables for a | |
45 | * <strong>single</strong> database. | |
46 | * | |
47 | * @author <a href="mailto:jvanzyl@zenplex.com">Jason van Zyl</a> | |
48 | * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> | |
49 | */ | |
50 | 0 | public class TorqueDataModelTask extends TexenTask { |
51 | /** | |
52 | * XML that describes the database model, this is transformed into the application model object. | |
53 | */ | |
54 | protected String xmlFile; | |
55 | ||
56 | /** Fileset of XML schemas which represent our data models. */ | |
57 | 0 | protected List<FileSet> filesets = new ArrayList<FileSet>(); |
58 | ||
59 | /** Data models that we collect. One from each XML schema file. */ | |
60 | 0 | protected List<Database> dataModels = new ArrayList<Database>(); |
61 | ||
62 | /** Velocity context which exposes our objects in the templates. */ | |
63 | protected Context context; | |
64 | ||
65 | /** | |
66 | * Map of data model name to database name. Should probably stick to the convention of them being the same but I | |
67 | * know right now in a lot of cases they won't be. | |
68 | */ | |
69 | protected Hashtable<String, String> dataModelDbMap; | |
70 | ||
71 | /** | |
72 | * Hashtable containing the names of all the databases in our collection of schemas. | |
73 | */ | |
74 | protected Hashtable<String, String> databaseNames; | |
75 | ||
76 | // !! This is probably a crappy idea having the sql file -> db map | |
77 | // here. I can't remember why I put it here at the moment ... | |
78 | // maybe I was going to map something else. It can probably | |
79 | // move into the SQL task. | |
80 | ||
81 | /** | |
82 | * Name of the properties file that maps an SQL file to a particular database. | |
83 | */ | |
84 | protected String sqldbmap; | |
85 | ||
86 | /** The target database(s) we are generating SQL for. */ | |
87 | private String targetDatabase; | |
88 | ||
89 | /** Target Java package to place the generated files in. */ | |
90 | private String targetPackage; | |
91 | ||
92 | /** | |
93 | * Set the sqldbmap. | |
94 | * | |
95 | * @param sqldbmap | |
96 | * th db map | |
97 | */ | |
98 | public void setSqlDbMap(String sqldbmap) { | |
99 | // !! Make all these references files not strings. | |
100 | 0 | this.sqldbmap = getProject().resolveFile(sqldbmap).toString(); |
101 | 0 | } |
102 | ||
103 | /** | |
104 | * Get the sqldbmap. | |
105 | * | |
106 | * @return String sqldbmap. | |
107 | */ | |
108 | public String getSqlDbMap() { | |
109 | 0 | return sqldbmap; |
110 | } | |
111 | ||
112 | /** | |
113 | * Return the data models that have been processed. | |
114 | * | |
115 | * @return List data models | |
116 | */ | |
117 | public List<Database> getDataModels() { | |
118 | 0 | return dataModels; |
119 | } | |
120 | ||
121 | /** | |
122 | * Return the data model to database name map. | |
123 | * | |
124 | * @return Hashtable data model name to database name map. | |
125 | */ | |
126 | public Hashtable<String, String> getDataModelDbMap() { | |
127 | 0 | return dataModelDbMap; |
128 | } | |
129 | ||
130 | /** | |
131 | * Get the xml schema describing the application model. | |
132 | * | |
133 | * @return String xml schema file. | |
134 | */ | |
135 | public String getXmlFile() { | |
136 | 0 | return xmlFile; |
137 | } | |
138 | ||
139 | /** | |
140 | * Set the xml schema describing the application model. | |
141 | * | |
142 | * @param xmlFile | |
143 | * The new XmlFile value | |
144 | */ | |
145 | public void setXmlFile(String xmlFile) { | |
146 | 0 | this.xmlFile = xmlFile; |
147 | 0 | } |
148 | ||
149 | /** | |
150 | * Adds a set of xml schema files (nested fileset attribute). | |
151 | * | |
152 | * @param set | |
153 | * a Set of xml schema files | |
154 | */ | |
155 | public void addFileset(FileSet set) { | |
156 | 0 | filesets.add(set); |
157 | 0 | } |
158 | ||
159 | /** | |
160 | * Get the current target database. | |
161 | * | |
162 | * @return String target database(s) | |
163 | */ | |
164 | public String getTargetDatabase() { | |
165 | 0 | return targetDatabase; |
166 | } | |
167 | ||
168 | /** | |
169 | * Set the current target database. (e.g. mysql, oracle, ..) | |
170 | */ | |
171 | public void setTargetDatabase(String targetDatabase) { | |
172 | 0 | this.targetDatabase = targetDatabase; |
173 | 0 | } |
174 | ||
175 | /** | |
176 | * Get the current target package. | |
177 | * | |
178 | * @return return target java package. | |
179 | */ | |
180 | public String getTargetPackage() { | |
181 | 0 | return targetPackage; |
182 | } | |
183 | ||
184 | /** | |
185 | * Set the current target package. This is where generated java classes will live. | |
186 | */ | |
187 | public void setTargetPackage(String targetPackage) { | |
188 | 0 | this.targetPackage = targetPackage; |
189 | 0 | } |
190 | ||
191 | /** | |
192 | * Return a SAX parser that implements the DatabaseParser interface | |
193 | */ | |
194 | protected DatabaseParser getDatabaseParser() { | |
195 | 0 | return new KualiXmlToAppData(getTargetDatabase(), getTargetPackage()); |
196 | } | |
197 | ||
198 | /** | |
199 | * Parse a schema XML File into a Database object | |
200 | */ | |
201 | protected Database getDataModel(File file) throws EngineException { | |
202 | // Get a handle to a parser | |
203 | 0 | DatabaseParser databaseParser = getDatabaseParser(); |
204 | ||
205 | // Parse the file into a database | |
206 | 0 | Database database = databaseParser.parseResource(file.toString()); |
207 | ||
208 | // Extract the filename | |
209 | 0 | database.setFileName(grokName(file.toString())); |
210 | ||
211 | // return the database | |
212 | 0 | return database; |
213 | } | |
214 | ||
215 | /** | |
216 | * Get the list of schema XML files from our filesets | |
217 | */ | |
218 | protected List<File> getDataModelFiles() { | |
219 | // Allocate some storage | |
220 | 0 | List<File> dataModelFiles = new ArrayList<File>(); |
221 | ||
222 | // Iterate through the filesets | |
223 | 0 | for (int i = 0; i < getFilesets().size(); i++) { |
224 | // Extract a fileset | |
225 | 0 | FileSet fs = getFilesets().get(i); |
226 | ||
227 | // Create a directory scanner | |
228 | 0 | DirectoryScanner ds = fs.getDirectoryScanner(getProject()); |
229 | ||
230 | // Figure out the directory to scan | |
231 | 0 | File srcDir = fs.getDir(getProject()); |
232 | ||
233 | // Scan the directory | |
234 | 0 | String[] dataModelFilesArray = ds.getIncludedFiles(); |
235 | ||
236 | // Add each file in the directory to our list | |
237 | 0 | for (int j = 0; j < dataModelFilesArray.length; j++) { |
238 | 0 | File file = new File(srcDir, dataModelFilesArray[j]); |
239 | 0 | dataModelFiles.add(file); |
240 | } | |
241 | } | |
242 | ||
243 | // Return the list of schema.xml files | |
244 | 0 | return dataModelFiles; |
245 | } | |
246 | ||
247 | /** | |
248 | * Parse schema XML files into Database objects | |
249 | */ | |
250 | protected List<Database> getPopulatedDataModels() throws EngineException { | |
251 | // Allocate some storage | |
252 | 0 | List<Database> databases = new ArrayList<Database>(); |
253 | ||
254 | // Only one file to parse | |
255 | 0 | if (getXmlFile() != null) { |
256 | // Parse the file into a database object | |
257 | 0 | Database database = getDataModel(new File(getXmlFile())); |
258 | // Add it to our list | |
259 | 0 | databases.add(database); |
260 | // we are done | |
261 | 0 | return databases; |
262 | } | |
263 | ||
264 | // Get the list of schema XML files to parse from our filesets | |
265 | 0 | List<File> dataModelFiles = getDataModelFiles(); |
266 | // Iterate through the list, parsing each schema.xml file into a database object | |
267 | 0 | for (File dataModelFile : dataModelFiles) { |
268 | // Parse a schema.xml file into a database object | |
269 | 0 | Database database = getDataModel(dataModelFile); |
270 | // Add the database object to our list | |
271 | 0 | databases.add(database); |
272 | 0 | } |
273 | // Return the list of database objects | |
274 | 0 | return databases; |
275 | } | |
276 | ||
277 | /** | |
278 | * Set up the initial context for generating SQL | |
279 | * | |
280 | * @return the context | |
281 | * @throws Exception | |
282 | */ | |
283 | public Context initControlContext() throws Exception { | |
284 | 0 | if (xmlFile == null && filesets.isEmpty()) { |
285 | 0 | throw new BuildException("You must specify an XML schema or fileset of XML schemas!"); |
286 | } | |
287 | ||
288 | try { | |
289 | 0 | dataModels = getPopulatedDataModels(); |
290 | 0 | } catch (EngineException ee) { |
291 | 0 | throw new BuildException(ee); |
292 | 0 | } |
293 | ||
294 | 0 | Iterator<Database> i = dataModels.iterator(); |
295 | 0 | databaseNames = new Hashtable<String, String>(); |
296 | 0 | dataModelDbMap = new Hashtable<String, String>(); |
297 | ||
298 | // Different datamodels may state the same database | |
299 | // names, we just want the unique names of databases. | |
300 | 0 | while (i.hasNext()) { |
301 | 0 | Database database = i.next(); |
302 | 0 | databaseNames.put(database.getName(), database.getName()); |
303 | 0 | dataModelDbMap.put(database.getFileName(), database.getName()); |
304 | 0 | } |
305 | ||
306 | 0 | context = new VelocityContext(); |
307 | ||
308 | // Place our set of data models into the context along | |
309 | // with the names of the databases as a convenience for now. | |
310 | 0 | context.put("dataModels", dataModels); |
311 | 0 | context.put("databaseNames", databaseNames); |
312 | 0 | context.put("targetDatabase", targetDatabase); |
313 | 0 | context.put("targetPackage", targetPackage); |
314 | ||
315 | 0 | return context; |
316 | } | |
317 | ||
318 | /** | |
319 | * Change type of "now" to java.util.Date | |
320 | * | |
321 | * @see org.apache.velocity.texen.ant.TexenTask#populateInitialContext(org.apache.velocity.context.Context) | |
322 | */ | |
323 | protected void populateInitialContext(Context context) throws Exception { | |
324 | 0 | super.populateInitialContext(context); |
325 | 0 | context.put("now", new Date()); |
326 | 0 | } |
327 | ||
328 | /** | |
329 | * Gets a name to use for the application's data model. | |
330 | * | |
331 | * @param xmlFile | |
332 | * The path to the XML file housing the data model. | |
333 | * @return The name to use for the <code>AppData</code>. | |
334 | */ | |
335 | private String grokName(String xmlFile) { | |
336 | // This can't be set from the file name as it is an unreliable | |
337 | // method of naming the descriptor. Not everyone uses the same | |
338 | // method as I do in the TDK. jvz. | |
339 | ||
340 | 0 | String name = "data-model"; |
341 | 0 | int i = xmlFile.lastIndexOf(System.getProperty("file.separator")); |
342 | 0 | if (i != -1) { |
343 | // Creep forward to the start of the file name. | |
344 | 0 | i++; |
345 | ||
346 | 0 | int j = xmlFile.lastIndexOf('.'); |
347 | 0 | if (i < j) { |
348 | 0 | name = xmlFile.substring(i, j); |
349 | } else { | |
350 | // Weirdo | |
351 | 0 | name = xmlFile.substring(i); |
352 | } | |
353 | } | |
354 | 0 | return name; |
355 | } | |
356 | ||
357 | /** | |
358 | * Override Texen's context properties to map the torque.xxx properties (including defaults set by the | |
359 | * org/apache/torque/defaults.properties) to just xxx. | |
360 | * | |
361 | * <p> | |
362 | * Also, move xxx.yyy properties to xxxYyy as Velocity doesn't like the xxx.yyy syntax. | |
363 | * </p> | |
364 | * | |
365 | * @param file | |
366 | * the file to read the properties from | |
367 | */ | |
368 | public void setContextProperties(String file) { | |
369 | 0 | super.setContextProperties(file); |
370 | ||
371 | // Map the torque.xxx elements from the env to the contextProperties | |
372 | 0 | Hashtable<?, ?> env = super.getProject().getProperties(); |
373 | 0 | for (Iterator<?> i = env.entrySet().iterator(); i.hasNext();) { |
374 | 0 | Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next(); |
375 | 0 | String key = (String) entry.getKey(); |
376 | 0 | if (key.startsWith("torque.")) { |
377 | 0 | String newKey = key.substring("torque.".length()); |
378 | 0 | int j = newKey.indexOf("."); |
379 | 0 | while (j != -1) { |
380 | 0 | newKey = newKey.substring(0, j) + StringUtils.capitalize(newKey.substring(j + 1)); |
381 | 0 | j = newKey.indexOf("."); |
382 | } | |
383 | ||
384 | 0 | contextProperties.setProperty(newKey, entry.getValue()); |
385 | } | |
386 | 0 | } |
387 | 0 | } |
388 | ||
389 | public List<FileSet> getFilesets() { | |
390 | 0 | return filesets; |
391 | } | |
392 | ||
393 | public void setFilesets(List<FileSet> filesets) { | |
394 | 0 | this.filesets = filesets; |
395 | 0 | } |
396 | } |