View Javadoc

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