%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.torque.engine.database.model.Database |
|
|
1 | package org.apache.torque.engine.database.model; |
|
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.util.ArrayList; |
|
23 | import java.util.Collections; |
|
24 | import java.util.HashMap; |
|
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.collections.map.ListOrderedMap; |
|
31 | import org.apache.commons.logging.Log; |
|
32 | import org.apache.commons.logging.LogFactory; |
|
33 | import org.apache.torque.engine.EngineException; |
|
34 | import org.apache.torque.engine.database.transform.DTDResolver; |
|
35 | import org.apache.torque.engine.platform.Platform; |
|
36 | import org.apache.torque.engine.platform.PlatformFactory; |
|
37 | import org.xml.sax.Attributes; |
|
38 | ||
39 | ||
40 | /** |
|
41 | * A class for holding application data structures. |
|
42 | * |
|
43 | * @author <a href="mailto:leon@opticode.co.za>Leon Messerschmidt</a> |
|
44 | * @author <a href="mailto:jmcnally@collab.net>John McNally</a> |
|
45 | * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a> |
|
46 | * @author <a href="mailto:dlr@collab.net>Daniel Rall</a> |
|
47 | * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a> |
|
48 | * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a> |
|
49 | * @version $Id: Database.java 473814 2006-11-11 22:30:30Z tv $ |
|
50 | */ |
|
51 | public class Database |
|
52 | { |
|
53 | /** Logging class from commons.logging */ |
|
54 | 306 | private static Log log = LogFactory.getLog(Database.class); |
55 | ||
56 | 884 | private String databaseType = null; |
57 | 884 | private List tableList = new ArrayList(100); |
58 | 884 | private Map domainMap = new HashMap(); |
59 | private String name; |
|
60 | private String javaName; |
|
61 | private String pkg; |
|
62 | private String baseClass; |
|
63 | private String basePeer; |
|
64 | private String defaultIdMethod; |
|
65 | private String defaultJavaType; |
|
66 | private String defaultJavaNamingMethod; |
|
67 | 884 | private Hashtable tablesByName = new Hashtable(); |
68 | 884 | private Hashtable tablesByJavaName = new Hashtable(); |
69 | private boolean heavyIndexing; |
|
70 | /** the name of the definition file */ |
|
71 | private String fileName; |
|
72 | 884 | private Map options = Collections.synchronizedMap(new ListOrderedMap()); |
73 | ||
74 | ||
75 | /** |
|
76 | * Creates a new instance for the specified database type. |
|
77 | * |
|
78 | * @param databaseType The default type for this database. |
|
79 | */ |
|
80 | public Database(String databaseType) |
|
81 | 884 | { |
82 | 884 | this.databaseType = databaseType; |
83 | 884 | } |
84 | ||
85 | /** |
|
86 | * Load the database object from an xml tag. |
|
87 | * |
|
88 | * @param attrib the xml attributes |
|
89 | */ |
|
90 | public void loadFromXML(Attributes attrib) |
|
91 | { |
|
92 | 833 | setName(attrib.getValue("name")); |
93 | 833 | pkg = attrib.getValue("package"); |
94 | 833 | baseClass = attrib.getValue("baseClass"); |
95 | 833 | basePeer = attrib.getValue("basePeer"); |
96 | 833 | defaultJavaType = attrib.getValue("defaultJavaType"); |
97 | 833 | defaultIdMethod = attrib.getValue("defaultIdMethod"); |
98 | 833 | defaultJavaNamingMethod = attrib.getValue("defaultJavaNamingMethod"); |
99 | 833 | if (defaultJavaNamingMethod == null) |
100 | { |
|
101 | 0 | defaultJavaNamingMethod = NameGenerator.CONV_METHOD_UNDERSCORE; |
102 | } |
|
103 | 833 | heavyIndexing = "true".equals(attrib.getValue("heavyIndexing")); |
104 | 833 | } |
105 | ||
106 | /** |
|
107 | * Get the name of the Database |
|
108 | * |
|
109 | * @return name of the Database |
|
110 | */ |
|
111 | public String getName() |
|
112 | { |
|
113 | 0 | return name; |
114 | } |
|
115 | ||
116 | /** |
|
117 | * Set the name of the Database |
|
118 | * |
|
119 | * @param name name of the Database |
|
120 | */ |
|
121 | public void setName(String name) |
|
122 | { |
|
123 | /** @task check this */ |
|
124 | // this.name = (name == null ? Torque.getDefaultDB() : name); |
|
125 | 833 | this.name = (name == null ? "default" : name); |
126 | 833 | } |
127 | ||
128 | public String getFileName() |
|
129 | { |
|
130 | 0 | return fileName; |
131 | } |
|
132 | ||
133 | public void setFileName(String name) |
|
134 | { |
|
135 | 0 | this.fileName = name; |
136 | 0 | } |
137 | ||
138 | /** |
|
139 | * Get the value of package. |
|
140 | * @return value of package. |
|
141 | */ |
|
142 | public String getPackage() |
|
143 | { |
|
144 | 4879 | return pkg; |
145 | } |
|
146 | ||
147 | /** |
|
148 | * Set the value of package. |
|
149 | * @param v Value to assign to package. |
|
150 | */ |
|
151 | public void setPackage(String v) |
|
152 | { |
|
153 | 816 | this.pkg = v; |
154 | 816 | } |
155 | ||
156 | /** |
|
157 | * Get the value of baseClass. |
|
158 | * @return value of baseClass. |
|
159 | */ |
|
160 | public String getBaseClass() |
|
161 | { |
|
162 | 0 | if (baseClass == null) |
163 | { |
|
164 | 0 | return "BaseObject"; |
165 | } |
|
166 | 0 | return baseClass; |
167 | } |
|
168 | ||
169 | /** |
|
170 | * Set the value of baseClass. |
|
171 | * @param v Value to assign to baseClass. |
|
172 | */ |
|
173 | public void setBaseClass(String v) |
|
174 | { |
|
175 | 0 | this.baseClass = v; |
176 | 0 | } |
177 | ||
178 | /** |
|
179 | * Get the value of basePeer. |
|
180 | * @return value of basePeer. |
|
181 | */ |
|
182 | public String getBasePeer() |
|
183 | { |
|
184 | 0 | if (basePeer == null) |
185 | { |
|
186 | 0 | return "BasePeer"; |
187 | } |
|
188 | 0 | return basePeer; |
189 | } |
|
190 | ||
191 | /** |
|
192 | * Set the value of basePeer. |
|
193 | * @param v Value to assign to basePeer. |
|
194 | */ |
|
195 | public void setBasePeer(String v) |
|
196 | { |
|
197 | 0 | this.basePeer = v; |
198 | 0 | } |
199 | ||
200 | /** |
|
201 | * Get the value of defaultIdMethod. |
|
202 | * @return value of defaultIdMethod. |
|
203 | */ |
|
204 | public String getDefaultIdMethod() |
|
205 | { |
|
206 | 4012 | return defaultIdMethod; |
207 | } |
|
208 | ||
209 | /** |
|
210 | * Set the value of defaultIdMethod. |
|
211 | * @param v Value to assign to defaultIdMethod. |
|
212 | */ |
|
213 | public void setDefaultIdMethod(String v) |
|
214 | { |
|
215 | 0 | this.defaultIdMethod = v; |
216 | 0 | } |
217 | ||
218 | /** |
|
219 | * Get type to use in Java sources (primitive || object) |
|
220 | * |
|
221 | * @return the type to use |
|
222 | */ |
|
223 | public String getDefaultJavaType() |
|
224 | { |
|
225 | 0 | return defaultJavaType; |
226 | } |
|
227 | ||
228 | /** |
|
229 | * Get the value of defaultJavaNamingMethod which specifies the |
|
230 | * method for converting schema names for table and column to Java names. |
|
231 | * |
|
232 | * @return The default naming conversion used by this database. |
|
233 | */ |
|
234 | public String getDefaultJavaNamingMethod() |
|
235 | { |
|
236 | 34221 | return defaultJavaNamingMethod; |
237 | } |
|
238 | ||
239 | /** |
|
240 | * Set the value of defaultJavaNamingMethod. |
|
241 | * @param v The default naming conversion for this database to use. |
|
242 | */ |
|
243 | public void setDefaultJavaNamingMethod(String v) |
|
244 | { |
|
245 | 0 | this.defaultJavaNamingMethod = v; |
246 | 0 | } |
247 | ||
248 | /** |
|
249 | * Get the value of heavyIndexing. |
|
250 | * @return value of heavyIndexing. |
|
251 | */ |
|
252 | public boolean isHeavyIndexing() |
|
253 | { |
|
254 | 3995 | return heavyIndexing; |
255 | } |
|
256 | ||
257 | /** |
|
258 | * Set the value of heavyIndexing. |
|
259 | * @param v Value to assign to heavyIndexing. |
|
260 | */ |
|
261 | public void setHeavyIndexing(boolean v) |
|
262 | { |
|
263 | 0 | this.heavyIndexing = v; |
264 | 0 | } |
265 | ||
266 | /** |
|
267 | * Return an List of all tables |
|
268 | * |
|
269 | * @return List of all tables |
|
270 | */ |
|
271 | public List getTables() |
|
272 | { |
|
273 | 850 | return tableList; |
274 | } |
|
275 | ||
276 | /** |
|
277 | * Return the table with the specified name. |
|
278 | * |
|
279 | * @param name table name |
|
280 | * @return A Table object. If it does not exist it returns null |
|
281 | */ |
|
282 | public Table getTable(String name) |
|
283 | { |
|
284 | 1309 | return (Table) tablesByName.get(name); |
285 | } |
|
286 | ||
287 | /** |
|
288 | * Return the table with the specified javaName. |
|
289 | * |
|
290 | * @param javaName name of the java object representing the table |
|
291 | * @return A Table object. If it does not exist it returns null |
|
292 | */ |
|
293 | public Table getTableByJavaName(String javaName) |
|
294 | { |
|
295 | 0 | return (Table) tablesByJavaName.get(javaName); |
296 | } |
|
297 | ||
298 | /** |
|
299 | * An utility method to add a new table from an xml attribute. |
|
300 | * |
|
301 | * @param attrib the xml attributes |
|
302 | * @return the created Table |
|
303 | */ |
|
304 | public Table addTable(Attributes attrib) |
|
305 | { |
|
306 | 3995 | Table tbl = new Table(); |
307 | 3995 | tbl.setDatabase(this); |
308 | 3995 | tbl.loadFromXML(attrib, this.getDefaultIdMethod()); |
309 | 3995 | addTable(tbl); |
310 | 3995 | return tbl; |
311 | } |
|
312 | ||
313 | /** |
|
314 | * Add a table to the list and sets the Database property to this Database |
|
315 | * |
|
316 | * @param tbl the table to add |
|
317 | */ |
|
318 | public void addTable(Table tbl) |
|
319 | { |
|
320 | 4012 | tbl.setDatabase(this); |
321 | 4012 | tableList.add(tbl); |
322 | 4012 | tablesByName.put(tbl.getName(), tbl); |
323 | 4012 | tablesByJavaName.put(tbl.getJavaName(), tbl); |
324 | 4012 | tbl.setPackage(getPackage()); |
325 | 4012 | } |
326 | ||
327 | public void addDomain(Domain domain) |
|
328 | { |
|
329 | 646 | domainMap.put(domain.getName(), domain); |
330 | 646 | } |
331 | ||
332 | public Domain getDomain(String domainName) |
|
333 | { |
|
334 | 1309 | return (Domain) domainMap.get(domainName); |
335 | } |
|
336 | ||
337 | protected String getDatabaseType() |
|
338 | { |
|
339 | 0 | return databaseType; |
340 | } |
|
341 | ||
342 | public void setDatabaseType(String databaseType) |
|
343 | { |
|
344 | 34 | this.databaseType = databaseType; |
345 | 34 | } |
346 | ||
347 | /** |
|
348 | * Returns the Platform implementation for this database. |
|
349 | * |
|
350 | * @return a Platform implementation |
|
351 | */ |
|
352 | public Platform getPlatform() |
|
353 | { |
|
354 | 62560 | return PlatformFactory.getPlatformFor(databaseType); |
355 | } |
|
356 | ||
357 | /** |
|
358 | * Determines if this database will be using the |
|
359 | * <code>IDMethod.ID_BROKER</code> to create ids for torque OM |
|
360 | * objects. |
|
361 | * @return true if there is at least one table in this database that |
|
362 | * uses the <code>IDMethod.ID_BROKER</code> method of generating |
|
363 | * ids. returns false otherwise. |
|
364 | */ |
|
365 | public boolean requiresIdTable() |
|
366 | { |
|
367 | 0 | Iterator iter = getTables().iterator(); |
368 | 0 | while (iter.hasNext()) |
369 | { |
|
370 | 0 | Table table = (Table) iter.next(); |
371 | 0 | if (table.getIdMethod().equals(IDMethod.ID_BROKER)) |
372 | { |
|
373 | 0 | return true; |
374 | } |
|
375 | 0 | } |
376 | 0 | return false; |
377 | } |
|
378 | ||
379 | /** |
|
380 | * Initializes the model. |
|
381 | * |
|
382 | * @throws EngineException |
|
383 | */ |
|
384 | public void doFinalInitialization() throws EngineException |
|
385 | { |
|
386 | 833 | Iterator iter = getTables().iterator(); |
387 | 4828 | while (iter.hasNext()) |
388 | { |
|
389 | 3995 | Table currTable = (Table) iter.next(); |
390 | ||
391 | // check schema integrity |
|
392 | // if idMethod="autoincrement", make sure a column is |
|
393 | // specified as autoIncrement="true" |
|
394 | // FIXME: Handle idMethod="native" via DB adapter. |
|
395 | // TODO autoincrement is no longer supported!!! |
|
396 | 3995 | if (currTable.getIdMethod().equals("autoincrement")) |
397 | { |
|
398 | 0 | boolean foundOne = false; |
399 | 0 | Iterator colIter = currTable.getColumns().iterator(); |
400 | 0 | while (colIter.hasNext() && !foundOne) |
401 | { |
|
402 | 0 | foundOne = ((Column) colIter.next()).isAutoIncrement(); |
403 | 0 | } |
404 | ||
405 | 0 | if (!foundOne) |
406 | { |
|
407 | 0 | String errorMessage = "Table '" + currTable.getName() |
408 | + "' is marked as autoincrement, but it does not " |
|
409 | + "have a column which declared as the one to " |
|
410 | + "auto increment (i.e. autoIncrement=\"true\")\n"; |
|
411 | 0 | throw new EngineException("Error in XML schema: " + errorMessage); |
412 | } |
|
413 | } |
|
414 | ||
415 | 3995 | currTable.doFinalInitialization(); |
416 | ||
417 | // setup reverse fk relations |
|
418 | 3995 | Iterator fks = currTable.getForeignKeys().iterator(); |
419 | 4454 | while (fks.hasNext()) |
420 | { |
|
421 | 459 | ForeignKey currFK = (ForeignKey) fks.next(); |
422 | 459 | Table foreignTable = getTable(currFK.getForeignTableName()); |
423 | 459 | if (foreignTable == null) |
424 | { |
|
425 | 0 | throw new EngineException("Attempt to set foreign" |
426 | + " key to nonexistent table, " |
|
427 | + currFK.getForeignTableName()); |
|
428 | } |
|
429 | else |
|
430 | { |
|
431 | // TODO check type and size |
|
432 | 459 | List referrers = foreignTable.getReferrers(); |
433 | 459 | if ((referrers == null || !referrers.contains(currFK))) |
434 | { |
|
435 | 459 | foreignTable.addReferrer(currFK); |
436 | } |
|
437 | ||
438 | // local column references |
|
439 | 459 | Iterator localColumnNames = currFK.getLocalColumns().iterator(); |
440 | 1071 | while (localColumnNames.hasNext()) |
441 | { |
|
442 | 612 | Column local = currTable |
443 | .getColumn((String) localColumnNames.next()); |
|
444 | // give notice of a schema inconsistency. |
|
445 | // note we do not prevent the npe as there is nothing |
|
446 | // that we can do, if it is to occur. |
|
447 | 612 | if (local == null) |
448 | { |
|
449 | 0 | throw new EngineException("Attempt to define foreign" |
450 | + " key with nonexistent column in table, " |
|
451 | + currTable.getName()); |
|
452 | } |
|
453 | else |
|
454 | { |
|
455 | //check for foreign pk's |
|
456 | 612 | if (local.isPrimaryKey()) |
457 | { |
|
458 | 0 | currTable.setContainsForeignPK(true); |
459 | } |
|
460 | } |
|
461 | 612 | } |
462 | ||
463 | // foreign column references |
|
464 | 459 | Iterator foreignColumnNames |
465 | = currFK.getForeignColumns().iterator(); |
|
466 | 1071 | while (foreignColumnNames.hasNext()) |
467 | { |
|
468 | 612 | String foreignColumnName = (String) foreignColumnNames.next(); |
469 | 612 | Column foreign = foreignTable.getColumn(foreignColumnName); |
470 | // if the foreign column does not exist, we may have an |
|
471 | // external reference or a misspelling |
|
472 | 612 | if (foreign == null) |
473 | { |
|
474 | 0 | throw new EngineException("Attempt to set foreign" |
475 | + " key to nonexistent column: table=" |
|
476 | + currTable.getName() + ", foreign column=" |
|
477 | + foreignColumnName); |
|
478 | } |
|
479 | else |
|
480 | { |
|
481 | 612 | foreign.addReferrer(currFK); |
482 | } |
|
483 | 612 | } |
484 | } |
|
485 | 459 | } |
486 | 3995 | } |
487 | 833 | } |
488 | ||
489 | /** |
|
490 | * Get the base name to use when creating related Java Classes. |
|
491 | * |
|
492 | * @return A Java syntax capatible version of the dbName using the method |
|
493 | * defined by the defaultJavaNamingMethod XML value. |
|
494 | */ |
|
495 | public String getJavaName() |
|
496 | { |
|
497 | 0 | if (javaName == null) |
498 | { |
|
499 | 0 | List inputs = new ArrayList(2); |
500 | 0 | inputs.add(name); |
501 | 0 | inputs.add(defaultJavaNamingMethod); |
502 | try |
|
503 | { |
|
504 | 0 | javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, |
505 | inputs); |
|
506 | } |
|
507 | 0 | catch (EngineException e) |
508 | { |
|
509 | 0 | log.error(e, e); |
510 | 0 | } |
511 | } |
|
512 | 0 | return javaName; |
513 | } |
|
514 | ||
515 | /** |
|
516 | * Convert dbName to a Java compatible name by the JavaName method only |
|
517 | * (ignores the defaultJavaNamingMethod). |
|
518 | * |
|
519 | * @return The current dbName converted to a standard format that can |
|
520 | * be used as part of a Java Object name. |
|
521 | */ |
|
522 | public String getStandardJavaName() |
|
523 | { |
|
524 | 0 | if (javaName == null) |
525 | { |
|
526 | 0 | List inputs = new ArrayList(2); |
527 | 0 | inputs.add(name); |
528 | 0 | inputs.add(NameGenerator.CONV_METHOD_JAVANAME); |
529 | try |
|
530 | { |
|
531 | 0 | javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, |
532 | inputs); |
|
533 | } |
|
534 | 0 | catch (EngineException e) |
535 | { |
|
536 | 0 | log.error(e, e); |
537 | 0 | } |
538 | } |
|
539 | 0 | return javaName; |
540 | } |
|
541 | ||
542 | /** |
|
543 | * Creats a string representation of this Database. |
|
544 | * The representation is given in xml format. |
|
545 | * |
|
546 | * @return string representation in xml |
|
547 | */ |
|
548 | public String toString() |
|
549 | { |
|
550 | 0 | StringBuffer result = new StringBuffer(); |
551 | ||
552 | 0 | result.append ("<?xml version=\ŕ.0\"?>\n"); |
553 | 0 | result.append ("<!DOCTYPE database SYSTEM \"" |
554 | + DTDResolver.WEB_SITE_DTD + "\">\n"); |
|
555 | 0 | result.append("<!-- Autogenerated by SQLToXMLSchema! -->\n"); |
556 | 0 | result.append("<database name=\"").append(getName()).append('"') |
557 | .append(" package=\"").append(getPackage()).append('"') |
|
558 | .append(" defaultIdMethod=\"").append(getDefaultIdMethod()) |
|
559 | .append('"') |
|
560 | .append(" baseClass=\"").append(getBaseClass()).append('"') |
|
561 | .append(" basePeer=\"").append(getBasePeer()).append('"') |
|
562 | .append(">\n"); |
|
563 | ||
564 | 0 | for (Iterator i = tableList.iterator(); i.hasNext();) |
565 | { |
|
566 | 0 | result.append(i.next()); |
567 | 0 | } |
568 | ||
569 | 0 | result.append("</database>"); |
570 | 0 | return result.toString(); |
571 | } |
|
572 | ||
573 | /** |
|
574 | * Add an XML Specified option key/value pair to this element's option set. |
|
575 | * |
|
576 | * @param key the key of the option. |
|
577 | * @param value the value of the option. |
|
578 | */ |
|
579 | public void addOption(String key, String value) |
|
580 | { |
|
581 | 0 | options.put(key, value); |
582 | 0 | } |
583 | ||
584 | /** |
|
585 | * Get the value that was associated with this key in an XML option |
|
586 | * element. |
|
587 | * |
|
588 | * @param key the key of the option. |
|
589 | * @return The value for the key or a null. |
|
590 | */ |
|
591 | public String getOption(String key) |
|
592 | { |
|
593 | 0 | return (String) options.get(key); |
594 | } |
|
595 | ||
596 | /** |
|
597 | * Gets the full ordered hashtable array of items specified by XML option |
|
598 | * statements under this element.<p> |
|
599 | * |
|
600 | * Note, this is not thread save but since it's only used for |
|
601 | * generation which is single threaded, there should be minimum |
|
602 | * danger using this in Velocity. |
|
603 | * |
|
604 | * @return An Map of all options. Will not be null but may be empty. |
|
605 | */ |
|
606 | public Map getOptions() |
|
607 | { |
|
608 | 0 | return options; |
609 | } |
|
610 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |