View Javadoc

1   package org.apache.torque.engine.database.model;
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.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.Hashtable;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.torque.engine.EngineException;
27  import org.apache.torque.engine.database.transform.DTDResolver;
28  import org.apache.torque.engine.platform.Platform;
29  import org.apache.torque.engine.platform.PlatformFactory;
30  import org.xml.sax.Attributes;
31  
32  
33  /***
34   * A class for holding application data structures.
35   *
36   * @author <a href="mailto:leon@opticode.co.za>Leon Messerschmidt</a>
37   * @author <a href="mailto:jmcnally@collab.net>John McNally</a>
38   * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a>
39   * @author <a href="mailto:dlr@collab.net>Daniel Rall</a>
40   * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
41   * @version $Id: Database.java 239626 2005-08-24 12:19:51Z henning $
42   */
43  public class Database
44  {
45      private String databaseType = null;
46      private List tableList = new ArrayList(100);
47      private Map domainMap = new HashMap();
48      private String name;
49      private String pkg;
50      private String baseClass;
51      private String basePeer;
52      private String defaultIdMethod;
53      private String defaultJavaType;
54      private String defaultJavaNamingMethod;
55      private Hashtable tablesByName = new Hashtable();
56      private Hashtable tablesByJavaName = new Hashtable();
57      private boolean heavyIndexing;
58      /*** the name of the definition file */
59      private String fileName;
60  
61      /***
62       * Creates a new instance for the specified database type.
63       *
64       * @param databaseType The default type for this database.
65       */
66      public Database(String databaseType)
67      {
68          this.databaseType = databaseType;
69      }
70  
71      /***
72       * Load the database object from an xml tag.
73       *
74       * @param attrib the xml attributes
75       */
76      public void loadFromXML(Attributes attrib)
77      {
78          setName(attrib.getValue("name"));
79          pkg = attrib.getValue("package");
80          baseClass = attrib.getValue("baseClass");
81          basePeer = attrib.getValue("basePeer");
82          defaultJavaType = attrib.getValue("defaultJavaType");
83          defaultIdMethod = attrib.getValue("defaultIdMethod");
84          defaultJavaNamingMethod = attrib.getValue("defaultJavaNamingMethod");
85          if (defaultJavaNamingMethod == null)
86          {
87              defaultJavaNamingMethod = NameGenerator.CONV_METHOD_UNDERSCORE;
88          }
89          heavyIndexing = "true".equals(attrib.getValue("heavyIndexing"));
90      }
91  
92      /***
93       * Get the name of the Database
94       *
95       * @return name of the Database
96       */
97      public String getName()
98      {
99          return name;
100     }
101 
102     /***
103      * Set the name of the Database
104      *
105      * @param name name of the Database
106      */
107     public void setName(String name)
108     {
109         /*** @task check this */
110 //        this.name = (name == null ? Torque.getDefaultDB() : name);
111         this.name = (name == null ? "default" : name);
112     }
113 
114     public String getFileName()
115     {
116         return fileName;
117     }
118 
119     public void setFileName(String name)
120     {
121         this.fileName = name;
122     }
123 
124     /***
125      * Get the value of package.
126      * @return value of package.
127      */
128     public String getPackage()
129     {
130         return pkg;
131     }
132 
133     /***
134      * Set the value of package.
135      * @param v  Value to assign to package.
136      */
137     public void setPackage(String v)
138     {
139         this.pkg = v;
140     }
141 
142     /***
143      * Get the value of baseClass.
144      * @return value of baseClass.
145      */
146     public String getBaseClass()
147     {
148         if (baseClass == null)
149         {
150             return "BaseObject";
151         }
152         return baseClass;
153     }
154 
155     /***
156      * Set the value of baseClass.
157      * @param v  Value to assign to baseClass.
158      */
159     public void setBaseClass(String v)
160     {
161         this.baseClass = v;
162     }
163 
164     /***
165      * Get the value of basePeer.
166      * @return value of basePeer.
167      */
168     public String getBasePeer()
169     {
170         if (basePeer == null)
171         {
172             return "BasePeer";
173         }
174         return basePeer;
175     }
176 
177     /***
178      * Set the value of basePeer.
179      * @param v Value to assign to basePeer.
180      */
181     public void setBasePeer(String v)
182     {
183         this.basePeer = v;
184     }
185 
186     /***
187      * Get the value of defaultIdMethod.
188      * @return value of defaultIdMethod.
189      */
190     public String getDefaultIdMethod()
191     {
192         return defaultIdMethod;
193     }
194 
195     /***
196      * Set the value of defaultIdMethod.
197      * @param v Value to assign to defaultIdMethod.
198      */
199     public void setDefaultIdMethod(String v)
200     {
201         this.defaultIdMethod = v;
202     }
203 
204     /***
205      * Get type to use in Java sources (primitive || object)
206      *
207      * @return the type to use
208      */
209     public String getDefaultJavaType()
210     {
211         return defaultJavaType;
212     }
213 
214     /***
215      * Get the value of defaultJavaNamingMethod which specifies the
216      * method for converting schema names for table and column to Java names.
217      *
218      * @return The default naming conversion used by this database.
219      */
220     public String getDefaultJavaNamingMethod()
221     {
222         return defaultJavaNamingMethod;
223     }
224 
225     /***
226      * Set the value of defaultJavaNamingMethod.
227      * @param v The default naming conversion for this database to use.
228      */
229     public void setDefaultJavaNamingMethod(String v)
230     {
231         this.defaultJavaNamingMethod = v;
232     }
233 
234     /***
235      * Get the value of heavyIndexing.
236      * @return value of heavyIndexing.
237      */
238     public boolean isHeavyIndexing()
239     {
240         return heavyIndexing;
241     }
242 
243     /***
244      * Set the value of heavyIndexing.
245      * @param v  Value to assign to heavyIndexing.
246      */
247     public void setHeavyIndexing(boolean v)
248     {
249         this.heavyIndexing = v;
250     }
251 
252     /***
253      * Return an List of all tables
254      *
255      * @return List of all tables
256      */
257     public List getTables()
258     {
259         return tableList;
260     }
261 
262     /***
263      * Return the table with the specified name.
264      *
265      * @param name table name
266      * @return A Table object.  If it does not exist it returns null
267      */
268     public Table getTable(String name)
269     {
270         return (Table) tablesByName.get(name);
271     }
272 
273     /***
274      * Return the table with the specified javaName.
275      *
276      * @param javaName name of the java object representing the table
277      * @return A Table object.  If it does not exist it returns null
278      */
279     public Table getTableByJavaName(String javaName)
280     {
281         return (Table) tablesByJavaName.get(javaName);
282     }
283 
284     /***
285      * An utility method to add a new table from an xml attribute.
286      *
287      * @param attrib the xml attributes
288      * @return the created Table
289      */
290     public Table addTable(Attributes attrib)
291     {
292         Table tbl = new Table();
293         tbl.setDatabase(this);
294         tbl.loadFromXML(attrib, this.getDefaultIdMethod());
295         addTable(tbl);
296         return tbl;
297     }
298 
299     /***
300      * Add a table to the list and sets the Database property to this Database
301      *
302      * @param tbl the table to add
303      */
304     public void addTable(Table tbl)
305     {
306         tbl.setDatabase(this);
307         tableList.add(tbl);
308         tablesByName.put(tbl.getName(), tbl);
309         tablesByJavaName.put(tbl.getJavaName(), tbl);
310         tbl.setPackage(getPackage());
311     }
312 
313     public void addDomain(Domain domain) {
314         domainMap.put(domain.getName(), domain);
315     }
316 
317     public Domain getDomain(String domainName) {
318         return (Domain) domainMap.get(domainName);
319     }
320 
321     protected String getDatabaseType()
322     {
323         return databaseType;
324     }
325 
326     public void setDatabaseType(String databaseType)
327     {
328         this.databaseType = databaseType;
329     }
330 
331     /***
332      * Returns the Platform implementation for this database.
333      *
334      * @return a Platform implementation
335      */
336     public Platform getPlatform()
337     {
338         return PlatformFactory.getPlatformFor(databaseType);
339     }
340 
341     /***
342      * Determines if this database will be using the
343      * <code>IDMethod.ID_BROKER</code> to create ids for torque OM
344      * objects.
345      * @return true if there is at least one table in this database that
346      * uses the <code>IDMethod.ID_BROKER</code> method of generating
347      * ids. returns false otherwise.
348      */
349     public boolean requiresIdTable()
350     {
351         Iterator iter = getTables().iterator();
352         while (iter.hasNext())
353         {
354             Table table = (Table) iter.next();
355             if (table.getIdMethod().equals(IDMethod.ID_BROKER))
356             {
357                 return true;
358             }
359         }
360         return false;
361     }
362 
363     /***
364      * Initializes the model.
365      *
366      * @throws EngineException
367      */
368     public void doFinalInitialization() throws EngineException
369     {
370         Iterator iter = getTables().iterator();
371         while (iter.hasNext())
372         {
373             Table currTable = (Table) iter.next();
374 
375             // check schema integrity
376             // if idMethod="autoincrement", make sure a column is
377             // specified as autoIncrement="true"
378             // FIXME: Handle idMethod="native" via DB adapter.
379             // TODO autoincrement is no longer supported!!!
380             if (currTable.getIdMethod().equals("autoincrement"))
381             {
382                 boolean foundOne = false;
383                 Iterator colIter = currTable.getColumns().iterator();
384                 while (colIter.hasNext() && !foundOne)
385                 {
386                     foundOne = ((Column) colIter.next()).isAutoIncrement();
387                 }
388 
389                 if (!foundOne)
390                 {
391                     String errorMessage = "Table '" + currTable.getName()
392                             + "' is marked as autoincrement, but it does not "
393                             + "have a column which declared as the one to "
394                             + "auto increment (i.e. autoIncrement=\"true\")\n";
395                     throw new EngineException("Error in XML schema: " + errorMessage);
396                 }
397             }
398 
399             currTable.doFinalInitialization();
400 
401             // setup reverse fk relations
402             Iterator fks = currTable.getForeignKeys().iterator();
403             while (fks.hasNext())
404             {
405                 ForeignKey currFK = (ForeignKey) fks.next();
406                 Table foreignTable = getTable(currFK.getForeignTableName());
407                 if (foreignTable == null)
408                 {
409                     throw new EngineException("Attempt to set foreign"
410                             + " key to nonexistent table, "
411                             + currFK.getForeignTableName());
412                 }
413                 else
414                 {
415                     // TODO check type and size
416                     List referrers = foreignTable.getReferrers();
417                     if ((referrers == null || !referrers.contains(currFK)))
418                     {
419                         foreignTable.addReferrer(currFK);
420                     }
421 
422                     // local column references
423                     Iterator localColumnNames = currFK.getLocalColumns().iterator();
424                     while (localColumnNames.hasNext())
425                     {
426                         Column local = currTable
427                                 .getColumn((String) localColumnNames.next());
428                         // give notice of a schema inconsistency.
429                         // note we do not prevent the npe as there is nothing
430                         // that we can do, if it is to occur.
431                         if (local == null)
432                         {
433                             throw new EngineException("Attempt to define foreign"
434                                     + " key with nonexistent column in table, "
435                                     + currTable.getName());
436                         }
437                         else
438                         {
439                             //check for foreign pk's
440                             if (local.isPrimaryKey())
441                             {
442                                 currTable.setContainsForeignPK(true);
443                             }
444                         }
445                     }
446 
447                     // foreign column references
448                     Iterator foreignColumnNames
449                             = currFK.getForeignColumns().iterator();
450                     while (foreignColumnNames.hasNext())
451                     {
452                         String foreignColumnName = (String) foreignColumnNames.next();
453                         Column foreign = foreignTable.getColumn(foreignColumnName);
454                         // if the foreign column does not exist, we may have an
455                         // external reference or a misspelling
456                         if (foreign == null)
457                         {
458                             throw new EngineException("Attempt to set foreign"
459                                     + " key to nonexistent column: table="
460                                     +  currTable.getName() + ", foreign column="
461                                     +  foreignColumnName);
462                         }
463                         else
464                         {
465                             foreign.addReferrer(currFK);
466                         }
467                     }
468                 }
469             }
470         }
471     }
472 
473     /***
474      * Creats a string representation of this Database.
475      * The representation is given in xml format.
476      *
477      * @return string representation in xml
478      */
479     public String toString()
480     {
481         StringBuffer result = new StringBuffer();
482 
483         result.append ("<?xml version=\"1.0\"?>\n");
484         result.append ("<!DOCTYPE database SYSTEM \""
485                 + DTDResolver.WEB_SITE_DTD + "\">\n");
486         result.append("<!-- Autogenerated by SQLToXMLSchema! -->\n");
487         result.append("<database name=\"").append(getName()).append('"')
488             .append(" package=\"").append(getPackage()).append('"')
489             .append(" defaultIdMethod=\"").append(getDefaultIdMethod())
490             .append('"')
491             .append(" baseClass=\"").append(getBaseClass()).append('"')
492             .append(" basePeer=\"").append(getBasePeer()).append('"')
493             .append(">\n");
494 
495         for (Iterator i = tableList.iterator(); i.hasNext();)
496         {
497             result.append(i.next());
498         }
499 
500         result.append("</database>");
501         return result.toString();
502     }
503 }