View Javadoc

1   package org.apache.torque.map;
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.lang.reflect.Method;
23  import java.text.MessageFormat;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.Map;
28  import java.util.StringTokenizer;
29  
30  import org.apache.commons.collections.map.ListOrderedMap;
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.torque.TorqueException;
33  import org.apache.torque.adapter.IDMethod;
34  import org.apache.torque.oid.IDBroker;
35  import org.apache.torque.oid.IdGenerator;
36  
37  /***
38   * DatabaseMap is used to model a database.
39   *
40   * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
41   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
42   * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
43   * @version $Id: DatabaseMap.java 476550 2006-11-18 16:08:37Z tfischer $
44   */
45  public class DatabaseMap implements java.io.Serializable
46  {
47      /***
48       * The character used by most implementations as the separator
49       * between name elements.
50       */
51      public static final char STD_SEPARATOR_CHAR = '_';
52  
53      /***
54       * The character which separates the schema name from the table name.
55       */
56      public static final char SCHEMA_SEPARATOR_CHAR = '.';
57  
58      /***
59       * Format used to create create the class name for initializing a DB
60       * specific map
61       */
62      public static final String INIT_CLASS_NAME_FORMAT =
63                                  "org.apache.torque.linkage.{0}MapInit";
64  
65      /***
66       * Error Messages for initialisation.
67       */
68      protected static final String[] ERROR_MESSAGES_INIT = {
69          "Invalid Torque OM setup for Database \"{0}\".\n"
70          + "Database Map initialization class, \"{1}\"," + " "
71          + "could not be found in your classpath.",
72          "Invalid Torque OM setup for Database \"{0}\".\n"
73          + "A class that the Database Map initialization class, \"{1}\", "
74          + "depends on could not be found.",
75          "Invalid Torque OM setup for Database \"{0}\".\n"
76          + "Something unexpected happened doing Class.forName(\"{1}\").  "
77          + "See the nested exception for details.",
78          "Invalid Torque OM setup for Database \"{0}\".\n"
79          + "An error occured invoking the init() method in class, \"{1}\""
80      };
81  
82      /*** The serialVersionUID for this class. */
83      private static final long serialVersionUID = 955251837095032274L;
84  
85      /*** The initial size of the Id-Generators map. */
86      private static final int ID_GENERATORS_INITIAL_SIZE = 6;
87  
88      /*** Name of the database. */
89      private String name;
90  
91      /*** Name of the tables in the database. */
92      private Map tables;
93  
94      /***
95       * A special table used to generate primary keys for the other
96       * tables.
97       */
98      private TableMap idTable = null;
99  
100     /*** The IDBroker that goes with the idTable. */
101     private IDBroker idBroker = null;
102 
103     /*** The IdGenerators, keyed by type of idMethod. */
104     private HashMap idGenerators;
105 
106     /*** Flag indicating that all tables have been loaded via initialize() */
107     private boolean isInitialized = false;
108 
109     /***
110      * Constructs a new DatabaseMap.
111      */
112     public DatabaseMap()
113     {
114         tables = Collections.synchronizedMap(new ListOrderedMap());
115         idGenerators = new HashMap(ID_GENERATORS_INITIAL_SIZE);
116     }
117 
118     /***
119      * Constructor.
120      *
121      * @param name Name of the database.
122      * @param numberOfTables Number of tables in the database.
123      * @deprecated use DatabaseMap() instead. Will be removed
124      *             in a future version of Torque.
125      */
126     public DatabaseMap(String name, int numberOfTables)
127     {
128         this.name = name;
129         tables = Collections.synchronizedMap(new ListOrderedMap());
130         idGenerators = new HashMap(ID_GENERATORS_INITIAL_SIZE);
131     }
132 
133     /***
134      * Constructor.
135      *
136      * @param name Name of the database.
137      * @deprecated use DatabaseMap() instead. Will be removed
138      *             in a future version of Torque.
139      */
140     public DatabaseMap(String name)
141     {
142         this.name = name;
143         tables = Collections.synchronizedMap(new ListOrderedMap());
144         idGenerators = new HashMap(ID_GENERATORS_INITIAL_SIZE);
145     }
146 
147     /***
148      * Does this database contain this specific table?
149      *
150      * @param table The TableMap representation of the table.
151      * @return True if the database contains the table.
152      */
153     public boolean containsTable(TableMap table)
154     {
155         return containsTable(table.getName());
156     }
157 
158     /***
159      * Does this database contain this specific table?
160      *
161      * @param name The String representation of the table.
162      * @return True if the database contains the table.
163      */
164     public boolean containsTable(String name)
165     {
166         if (name.indexOf('.') > 0)
167         {
168             name = name.substring(0, name.indexOf('.'));
169         }
170         return tables.containsKey(name);
171     }
172 
173     /***
174      * Get the ID table for this database.
175      *
176      * @return A TableMap.
177      */
178     public TableMap getIdTable()
179     {
180         return idTable;
181     }
182 
183     /***
184      * Get the IDBroker for this database.
185      *
186      * @return An IDBroker.
187      * @deprecated Will be removed in a future version of Torque.
188      *             Use DatabaseInfo#getIdBroker() instead
189      *             to access the IDBroker.
190      */
191     public IDBroker getIDBroker()
192     {
193         return idBroker;
194     }
195 
196     /***
197      * Get the name of this database.
198      *
199      * @return A String.
200      * @deprecated Will be removed in a future version of Torque.
201      *             Use the name of the corresponding database instead.
202      */
203     public String getName()
204     {
205         return name;
206     }
207 
208     /***
209      * Get a TableMap for the table by name. <p>
210      *
211      * Note that by default Torque uses lazy initialization to minimize
212      * memory usage and startup time.  However, if an OM or PEER class
213      * has not called the table's MapBuilder class, it will not be here.
214      * See the optional initialize method if you need full OM Mapping.<p>
215      *
216      * @param name Name of the table.
217      * @return A TableMap, null if the table was not found.
218      */
219     public TableMap getTable(String name)
220     {
221         return (TableMap) tables.get(name);
222     }
223 
224     /***
225      * Get a TableMap[] of all of the tables in the database.<P>
226      *
227      * Note that by default Torque uses lazy initialization to minimize
228      * memory usage and startup time.  However, if an OM or PEER class
229      * has not called the table's MapBuilder class, it will not be here.
230      * See the optional initialize method if you need full OM Mapping.<p>
231      *
232      * @return A TableMap[].
233      */
234     public TableMap[] getTables()
235     {
236         TableMap[] dbTables = new TableMap[tables.size()];
237         synchronized (tables)
238         {
239             Iterator it = tables.values().iterator();
240             int i = 0;
241             while (it.hasNext())
242             {
243                 dbTables[i++] = (TableMap) it.next();
244             }
245         }
246         return dbTables;
247     }
248 
249     /***
250      * Add a new table to the database by name.  It creates an empty
251      * TableMap that you need to populate.
252      *
253      * @param tableName The name of the table.
254      */
255     public void addTable(String tableName)
256     {
257         TableMap tmap = new TableMap(tableName, this);
258         tables.put(tableName, tmap);
259     }
260 
261     /***
262      * Add a new table to the database by name.  It creates an empty
263      * TableMap that you need to populate.
264      *
265      * @param tableName The name of the table.
266      * @param numberOfColumns The number of columns in the table.
267      */
268     public void addTable(String tableName, int numberOfColumns)
269     {
270         TableMap tmap = new TableMap(tableName, numberOfColumns, this);
271         tables.put(tableName, tmap);
272     }
273 
274     /***
275      * Add a new TableMap to the database.
276      *
277      * @param map The TableMap representation.
278      */
279     public void addTable(TableMap map)
280     {
281         tables.put(map.getName(), map);
282     }
283 
284     /***
285      * Set the ID table for this database.
286      *
287      * @param idTable The TableMap representation for the ID table.
288      */
289     public void setIdTable(TableMap idTable)
290     {
291         this.idTable = idTable;
292         addTable(idTable);
293     }
294 
295     /***
296      * Set the ID table for this database.
297      *
298      * @param tableName The name for the ID table.
299      */
300     public void setIdTable(String tableName)
301     {
302         TableMap tmap = new TableMap(tableName, this);
303         setIdTable(tmap);
304     }
305 
306     /***
307      * Add a type of id generator for access by a TableMap.
308      *
309      * @param type a <code>String</code> value
310      * @param idGen an <code>IdGenerator</code> value
311      * @deprecated use DatabaseInfo.addGenerator() instead.
312      *             Will be removed in a future version of Torque.
313      */
314     public void addIdGenerator(String type, IdGenerator idGen)
315     {
316         idGenerators.put(type, idGen);
317     }
318 
319     /***
320      * Get a type of id generator.  Valid values are listed in the
321      * {@link org.apache.torque.adapter.IDMethod} interface.
322      *
323      * @param type a <code>String</code> value
324      * @return an <code>IdGenerator</code> value
325      * @deprecated use DatabaseInfo.getIdGenerator() instead.
326      *             Will be removed in a future version of Torque.
327      */
328     public IdGenerator getIdGenerator(String type)
329     {
330         return (IdGenerator) idGenerators.get(type);
331     }
332 
333     /***
334      * Creates the Idbroker for this DatabaseMap.
335      * If an IDBroker already exists for the DatabaseMap, the method
336      * does nothing.
337      * @return true if a new IdBroker was created, false otherwise.
338      * @deprecated Will be removed in a future version of Torque.
339      *             Use DatabaseInfo.startIdBroker() instead.
340      */
341     public synchronized boolean startIdBroker()
342     {
343         if (idBroker == null)
344         {
345             setIdTable("ID_TABLE");
346             TableMap tMap = getIdTable();
347             tMap.addPrimaryKey("ID_TABLE_ID", new Integer(0));
348             tMap.addColumn("TABLE_NAME", "");
349             tMap.addColumn("NEXT_ID", new Integer(0));
350             tMap.addColumn("QUANTITY", new Integer(0));
351             idBroker = new IDBroker(idTable);
352             addIdGenerator(IDMethod.ID_BROKER, idBroker);
353             return true;
354         }
355         return false;
356     }
357 
358     /***
359      * Fully populate this DatabaseMap with all the TablesMaps.  This
360      * is only needed if the application needs to use the complete OM
361      * mapping information.  Otherwise, the OM Mapping information
362      * will be populated as needed by OM and Peer classes.  An example
363      * of how to initialize the map info from the application:<p>
364      *
365      *   <code>
366      *   DatabaseMap dbMap = Torque.getDatabaseMap( dbName );
367      *   try {
368      *      dbMap.initialize();
369      *   } catch ( TorqueException e ) {
370      *      ... error handling
371      *   }
372      *   </code>
373      *
374      * Note that Torque database names are case sensitive and this DB
375      * map must be retrieved with the exact name used in the XML schema.<p>
376      *
377      * This uses Java reflection methods to locate and run the
378      * init() method of a class generated in the org.apache.torque.linkage
379      * package with a name based on the XML Database name value, e.g.
380      * org.apache.torque.linkage.DefaultMapInit<p>
381      *
382      * Some misconfiguration situations that could cause this method to fail
383      * are:<p>
384      *
385      * It was used with a Torque OM set of classes generated by V3.2 or older;
386      * <br>
387      * The class(es) in the org.apache.torque.linkage package were not included
388      * with the other generated class files (e.g. the jar file creation process
389      * only included com.* and not org.* files).<p>
390      *
391      * @throws TorqueException If an error is encountered locating and calling
392      *                          the init method.
393      */
394     public synchronized void initialize() throws TorqueException
395     {
396         if (isInitialized)
397         {
398             return;
399         }
400         String initClassName = MessageFormat.format(INIT_CLASS_NAME_FORMAT,
401                 new Object[] {
402                     javanameMethod(getName())
403                 });
404 
405         Class initClass = null;
406         try
407         {
408             initClass = Class.forName(initClassName);
409         }
410         catch (ClassNotFoundException e)
411         {
412             throw new TorqueException(MessageFormat.format(
413                     ERROR_MESSAGES_INIT[0],
414                     new Object[] {
415                         getName(),
416                         initClassName
417                     }),
418                     e);
419         }
420         catch (LinkageError e)
421         {
422             throw new TorqueException(MessageFormat.format(
423                     ERROR_MESSAGES_INIT[1],
424                     new Object[] {
425                         getName(), initClassName
426                     }),
427                     e);
428         }
429         catch (Throwable e)
430         {
431             throw new TorqueException(MessageFormat.format(
432                     ERROR_MESSAGES_INIT[2],
433                     new Object[] {
434                         getName(), initClassName
435                     }),
436                     e);
437         }
438         try
439         {
440             Method initMethod = initClass.getMethod("init", (Class []) null);
441             initMethod.invoke(null, (Object []) null);
442         }
443         catch (Exception e)
444         {
445             throw new TorqueException(MessageFormat.format(
446                     ERROR_MESSAGES_INIT[3],
447                     new Object[] {
448                         getName(), initClassName
449                     }),
450                     e);
451         }
452         isInitialized = true;
453     }
454 
455     /***
456      * Converts a database schema name to java object name.  Operates
457      * same as underscoreMethod but does not convert anything to
458      * lowercase.  This must match the javaNameMethod in the
459      * JavaNameGenerator class in Generator code.
460      *
461      * @param schemaName name to be converted.
462      * @return converted name.
463      *
464      * @see org.apache.torque.engine.database.model.NameGenerator
465      */
466     protected String javanameMethod(String schemaName)
467     {
468         StringBuffer result = new StringBuffer();
469         StringTokenizer tok = new StringTokenizer
470             (schemaName, String.valueOf(STD_SEPARATOR_CHAR));
471         while (tok.hasMoreTokens())
472         {
473             String namePart = (String) tok.nextElement();
474             result.append(StringUtils.capitalize(namePart));
475         }
476 
477         // remove the SCHEMA_SEPARATOR_CHARs and capitalize
478         // the tokens
479         schemaName = result.toString();
480         result = new StringBuffer();
481 
482         tok = new StringTokenizer
483             (schemaName, String.valueOf(SCHEMA_SEPARATOR_CHAR));
484         while (tok.hasMoreTokens())
485         {
486             String namePart = (String) tok.nextElement();
487             result.append(StringUtils.capitalize(namePart));
488         }
489         return result.toString();
490     }
491 }