Coverage report

  %line %branch
org.apache.torque.task.TorqueJDBCTransformTask
0% 
0% 

 1  
 package org.apache.torque.task;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2004 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.FileOutputStream;
 20  
 import java.io.PrintWriter;
 21  
 
 22  
 import java.sql.Connection;
 23  
 import java.sql.DatabaseMetaData;
 24  
 import java.sql.DriverManager;
 25  
 import java.sql.ResultSet;
 26  
 import java.sql.SQLException;
 27  
 import java.sql.Types;
 28  
 
 29  
 import java.util.ArrayList;
 30  
 import java.util.Collection;
 31  
 import java.util.Hashtable;
 32  
 import java.util.Iterator;
 33  
 import java.util.List;
 34  
 
 35  
 import org.apache.tools.ant.BuildException;
 36  
 import org.apache.tools.ant.Task;
 37  
 
 38  
 import org.apache.torque.engine.database.model.TypeMap;
 39  
 import org.apache.torque.engine.database.transform.DTDResolver;
 40  
 
 41  
 import org.apache.xerces.dom.DocumentImpl;
 42  
 import org.apache.xerces.dom.DocumentTypeImpl;
 43  
 
 44  
 import org.apache.xml.serialize.Method;
 45  
 import org.apache.xml.serialize.OutputFormat;
 46  
 import org.apache.xml.serialize.XMLSerializer;
 47  
 
 48  
 import org.w3c.dom.Element;
 49  
 import org.w3c.dom.Node;
 50  
 
 51  
 /**
 52  
  * This class generates an XML schema of an existing database from
 53  
  * JDBC metadata.
 54  
  *
 55  
  * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
 56  
  * @author <a href="mailto:fedor.karpelevitch@barra.com">Fedor Karpelevitch</a>
 57  
  * @version $Id: TorqueJDBCTransformTask.java,v 1.6.2.2 2004/05/20 04:35:14 seade Exp $
 58  
  */
 59  0
 public class TorqueJDBCTransformTask extends Task
 60  
 {
 61  
     /** Name of XML database schema produced. */
 62  
     protected String xmlSchema;
 63  
 
 64  
     /** JDBC URL. */
 65  
     protected String dbUrl;
 66  
 
 67  
     /** JDBC driver. */
 68  
     protected String dbDriver;
 69  
 
 70  
     /** JDBC user name. */
 71  
     protected String dbUser;
 72  
 
 73  
     /** JDBC password. */
 74  
     protected String dbPassword;
 75  
 
 76  
     /** DB schema to use. */
 77  
     protected String dbSchema;
 78  
 
 79  
     /** DOM document produced. */
 80  
     protected DocumentImpl doc;
 81  
 
 82  
     /** The document root element. */
 83  
     protected Node databaseNode;
 84  
 
 85  
     /** Hashtable of columns that have primary keys. */
 86  
     protected Hashtable primaryKeys;
 87  
 
 88  
     /** Hashtable to track what table a column belongs to. */
 89  
     protected Hashtable columnTableMap;
 90  
 
 91  
     protected boolean sameJavaName;
 92  
 
 93  
     private XMLSerializer xmlSerializer;
 94  
 
 95  
     public String getDbSchema()
 96  
     {
 97  0
         return dbSchema;
 98  
     }
 99  
 
 100  
     public void setDbSchema(String dbSchema)
 101  
     {
 102  0
         this.dbSchema = dbSchema;
 103  0
     }
 104  
 
 105  
     public void setDbUrl(String v)
 106  
     {
 107  0
         dbUrl = v;
 108  0
     }
 109  
 
 110  
     public void setDbDriver(String v)
 111  
     {
 112  0
         dbDriver = v;
 113  0
     }
 114  
 
 115  
     public void setDbUser(String v)
 116  
     {
 117  0
         dbUser = v;
 118  0
     }
 119  
 
 120  
     public void setDbPassword(String v)
 121  
     {
 122  0
         dbPassword = v;
 123  0
     }
 124  
 
 125  
     public void setOutputFile (String v)
 126  
     {
 127  0
         xmlSchema = v;
 128  0
     }
 129  
 
 130  
     public void setSameJavaName(boolean v)
 131  
     {
 132  0
         this.sameJavaName = v;
 133  0
     }
 134  
 
 135  
     public boolean isSameJavaName()
 136  
     {
 137  0
         return this.sameJavaName;
 138  
     }
 139  
 
 140  
     /**
 141  
      * Default constructor.
 142  
      *
 143  
      * @throws BuildException
 144  
      */
 145  
     public void execute() throws BuildException
 146  
     {
 147  0
         log("Torque - JDBCToXMLSchema starting");
 148  0
         log("Your DB settings are:");
 149  0
         log("driver : " + dbDriver);
 150  0
         log("URL : " + dbUrl);
 151  0
         log("user : " + dbUser);
 152  
         // log("password : " + dbPassword);
 153  0
         log("schema : " + dbSchema);
 154  
 
 155  0
         DocumentTypeImpl docType = new DocumentTypeImpl(null, "database", null,
 156  
                 DTDResolver.WEB_SITE_DTD);
 157  0
         doc = new DocumentImpl(docType);
 158  0
         doc.appendChild(doc.createComment(
 159  
                 " Autogenerated by JDBCToXMLSchema! "));
 160  
 
 161  
         try
 162  
         {
 163  0
             generateXML();
 164  0
             log(xmlSchema);
 165  0
             xmlSerializer = new XMLSerializer(
 166  
                     new PrintWriter(
 167  
                     new FileOutputStream(xmlSchema)),
 168  
                     new OutputFormat(Method.XML, null, true));
 169  0
             xmlSerializer.serialize(doc);
 170  
         }
 171  0
         catch (Exception e)
 172  
         {
 173  0
             throw new BuildException(e);
 174  0
         }
 175  0
         log("Torque - JDBCToXMLSchema finished");
 176  0
     }
 177  
 
 178  
     /**
 179  
      * Generates an XML database schema from JDBC metadata.
 180  
      *
 181  
      * @throws Exception a generic exception.
 182  
      */
 183  
     public void generateXML() throws Exception
 184  
     {
 185  
         // Load the Interbase Driver.
 186  0
         Class.forName(dbDriver);
 187  0
         log("DB driver sucessfuly instantiated");
 188  
 
 189  
         // Attemtp to connect to a database.
 190  0
         Connection con = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
 191  0
         log("DB connection established");
 192  
 
 193  
         // Get the database Metadata.
 194  0
         DatabaseMetaData dbMetaData = con.getMetaData();
 195  
 
 196  
         // The database map.
 197  0
         List tableList = getTableNames(dbMetaData);
 198  
 
 199  0
         databaseNode = doc.createElement("database");
 200  
 
 201  
         // Build a database-wide column -> table map.
 202  0
         columnTableMap = new Hashtable();
 203  
 
 204  0
         log("Building column/table map...");
 205  0
         for (int i = 0; i < tableList.size(); i++)
 206  
         {
 207  0
             String curTable = (String) tableList.get(i);
 208  0
             List columns = getColumns(dbMetaData, curTable);
 209  
 
 210  0
             for (int j = 0; j < columns.size(); j++)
 211  
             {
 212  0
                 List col = (List) columns.get(j);
 213  0
                 String name = (String) col.get(0);
 214  
 
 215  0
                 columnTableMap.put(name, curTable);
 216  
             }
 217  
         }
 218  
 
 219  0
         for (int i = 0; i < tableList.size(); i++)
 220  
         {
 221  
             // Add Table.
 222  0
             String curTable = (String) tableList.get(i);
 223  
             // dbMap.addTable(curTable);
 224  0
             log("Processing table: " + curTable);
 225  
 
 226  0
             Element table = doc.createElement("table");
 227  0
             table.setAttribute("name", curTable);
 228  0
             if (isSameJavaName())
 229  
             {
 230  0
                 table.setAttribute("javaName", curTable);
 231  
             }
 232  
 
 233  
             // Add Columns.
 234  
             // TableMap tblMap = dbMap.getTable(curTable);
 235  
 
 236  0
             List columns = getColumns(dbMetaData, curTable);
 237  0
             List primKeys = getPrimaryKeys(dbMetaData, curTable);
 238  0
             Collection forgnKeys = getForeignKeys(dbMetaData, curTable);
 239  
 
 240  
             // Set the primary keys.
 241  0
             primaryKeys = new Hashtable();
 242  
 
 243  0
             for (int k = 0; k < primKeys.size(); k++)
 244  
             {
 245  0
                 String curPrimaryKey = (String) primKeys.get(k);
 246  0
                 primaryKeys.put(curPrimaryKey, curPrimaryKey);
 247  
             }
 248  
 
 249  0
             for (int j = 0; j < columns.size(); j++)
 250  
             {
 251  0
                 List col = (List) columns.get(j);
 252  0
                 String name = (String) col.get(0);
 253  0
                 Integer type = ((Integer) col.get(1));
 254  0
                 int size = ((Integer) col.get(2)).class="keyword">intValue();
 255  
 
 256  
                 // From DatabaseMetaData.java
 257  
                 //
 258  
                 // Indicates column might not allow NULL values.  Huh?
 259  
                 // Might? Boy, that's a definitive answer.
 260  
                 /* int columnNoNulls = 0; */
 261  
 
 262  
                 // Indicates column definitely allows NULL values.
 263  
                 /* int columnNullable = 1; */
 264  
 
 265  
                 // Indicates NULLABILITY of column is unknown.
 266  
                 /* int columnNullableUnknown = 2; */
 267  
 
 268  0
                 Integer nullType = (Integer) col.get(3);
 269  0
                 String defValue = (String) col.get(4);
 270  
 
 271  0
                 Element column = doc.createElement("column");
 272  0
                 column.setAttribute("name", name);
 273  0
                 if (isSameJavaName())
 274  
                 {
 275  0
                     column.setAttribute("javaName", name);
 276  
                 }
 277  0
                 column.setAttribute("type", TypeMap.getTorqueType(type));
 278  
 
 279  0
                 if (size > 0 && (type.intValue() == Types.CHAR
 280  
                         || type.intValue() == Types.VARCHAR
 281  
                         || type.intValue() == Types.LONGVARCHAR
 282  
                         || type.intValue() == Types.DECIMAL
 283  
                         || type.intValue() == Types.NUMERIC))
 284  
                 {
 285  0
                     column.setAttribute("size", String.valueOf(size));
 286  
                 }
 287  
 
 288  0
                 if (nullType.intValue() == 0)
 289  
                 {
 290  0
                     column.setAttribute("required", "true");
 291  
                 }
 292  
 
 293  0
                 if (primaryKeys.containsKey(name))
 294  
                 {
 295  0
                     column.setAttribute("primaryKey", "true");
 296  
                 }
 297  
 
 298  0
                 if (defValue != null)
 299  
                 {
 300  
                     // trim out parens & quotes out of def value.
 301  
                     // makes sense for MSSQL. not sure about others.
 302  0
                     if (defValue.startsWith("(") && defValue.endsWith(")"))
 303  
                     {
 304  0
                         defValue = defValue.substring(1, defValue.length() - 1);
 305  
                     }
 306  
 
 307  0
                     if (defValue.startsWith("'") && defValue.endsWith("'"))
 308  
                     {
 309  0
                         defValue = defValue.substring(1, defValue.length() - 1);
 310  
                     }
 311  
 
 312  0
                     column.setAttribute("default", defValue);
 313  
                 }
 314  0
                 table.appendChild(column);
 315  
             }
 316  
 
 317  
             // Foreign keys for this table.
 318  0
             for (Iterator l = class="keyword">forgnKeys.iterator(); l.hasNext();)
 319  
             {
 320  0
                 Object[] forKey = (Object[]) l.next();
 321  0
                 String foreignKeyTable = (String) forKey[0];
 322  0
                 List refs = (List) forKey[1];
 323  0
                 Element fk = doc.createElement("foreign-key");
 324  0
                 fk.setAttribute("foreignTable", foreignKeyTable);
 325  0
                 for (int m = 0; m < refs.size(); m++)
 326  
                 {
 327  0
                     Element ref = doc.createElement("reference");
 328  0
                     String[] refData = (String[]) refs.get(m);
 329  0
                     ref.setAttribute("local", refData[0]);
 330  0
                     ref.setAttribute("foreign", refData[1]);
 331  0
                     fk.appendChild(ref);
 332  
                 }
 333  0
                 table.appendChild(fk);
 334  
             }
 335  0
             databaseNode.appendChild(table);
 336  
         }
 337  0
         doc.appendChild(databaseNode);
 338  0
     }
 339  
 
 340  
     /**
 341  
      * Get all the table names in the current database that are not
 342  
      * system tables.
 343  
      *
 344  
      * @param dbMeta JDBC database metadata.
 345  
      * @return The list of all the tables in a database.
 346  
      * @throws SQLException
 347  
      */
 348  
     public List getTableNames(DatabaseMetaData dbMeta)
 349  
         throws SQLException
 350  
     {
 351  0
         log("Getting table list...");
 352  0
         List tables = new ArrayList();
 353  0
         ResultSet tableNames = null;
 354  
         // these are the entity types we want from the database
 355  0
         String[] types = {"TABLE", "VIEW"};
 356  
         try
 357  
         {
 358  0
             tableNames = dbMeta.getTables(null, dbSchema, "%", types);
 359  0
             while (tableNames.next())
 360  
             {
 361  0
                 String name = tableNames.getString(3);
 362  0
                 String type = tableNames.getString(4);
 363  0
                 tables.add(name);
 364  
             }
 365  
         }
 366  
         finally
 367  
         {
 368  0
             if (tableNames != null)
 369  
             {
 370  0
                 tableNames.close();
 371  
             }
 372  
         }
 373  0
         return tables;
 374  
     }
 375  
 
 376  
     /**
 377  
      * Retrieves all the column names and types for a given table from
 378  
      * JDBC metadata.  It returns a List of Lists.  Each element
 379  
      * of the returned List is a List with:
 380  
      *
 381  
      * element 0 => a String object for the column name.
 382  
      * element 1 => an Integer object for the column type.
 383  
      * element 2 => size of the column.
 384  
      * element 3 => null type.
 385  
      *
 386  
      * @param dbMeta JDBC metadata.
 387  
      * @param tableName Table from which to retrieve column information.
 388  
      * @return The list of columns in <code>tableName</code>.
 389  
      * @throws SQLException
 390  
      */
 391  
     public List getColumns(DatabaseMetaData dbMeta, String tableName)
 392  
             throws SQLException
 393  
     {
 394  0
         List columns = new ArrayList();
 395  0
         ResultSet columnSet = null;
 396  
         try
 397  
         {
 398  0
             columnSet = dbMeta.getColumns(null, dbSchema, tableName, class="keyword">null);
 399  0
             while (columnSet.next())
 400  
             {
 401  0
                 String name = columnSet.getString(4);
 402  0
                 Integer sqlType = new Integer(columnSet.getString(5));
 403  0
                 Integer size = new Integer(columnSet.getInt(7));
 404  0
                 Integer nullType = new Integer(columnSet.getInt(11));
 405  0
                 String defValue = columnSet.getString(13);
 406  
 
 407  0
                 List col = new ArrayList(5);
 408  0
                 col.add(name);
 409  0
                 col.add(sqlType);
 410  0
                 col.add(size);
 411  0
                 col.add(nullType);
 412  0
                 col.add(defValue);
 413  0
                 columns.add(col);
 414  
             }
 415  
         }
 416  
         finally
 417  
         {
 418  0
             if (columnSet != null)
 419  
             {
 420  0
                 columnSet.close();
 421  
             }
 422  
         }
 423  0
         return columns;
 424  
     }
 425  
 
 426  
     /**
 427  
      * Retrieves a list of the columns composing the primary key for a given
 428  
      * table.
 429  
      *
 430  
      * @param dbMeta JDBC metadata.
 431  
      * @param tableName Table from which to retrieve PK information.
 432  
      * @return A list of the primary key parts for <code>tableName</code>.
 433  
      * @throws SQLException
 434  
      */
 435  
     public List getPrimaryKeys(DatabaseMetaData dbMeta, String tableName)
 436  
             throws SQLException
 437  
     {
 438  0
         List pk = new ArrayList();
 439  0
         ResultSet parts = null;
 440  
         try
 441  
         {
 442  0
             parts = dbMeta.getPrimaryKeys(null, dbSchema, tableName);
 443  0
             while (parts.next())
 444  
             {
 445  0
                 pk.add(parts.getString(4));
 446  
             }
 447  
         }
 448  
         finally
 449  
         {
 450  0
             if (parts != null)
 451  
             {
 452  0
                 parts.close();
 453  
             }
 454  
         }
 455  0
         return pk;
 456  
     }
 457  
 
 458  
     /**
 459  
      * Retrieves a list of foreign key columns for a given table.
 460  
      *
 461  
      * @param dbMeta JDBC metadata.
 462  
      * @param tableName Table from which to retrieve FK information.
 463  
      * @return A list of foreign keys in <code>tableName</code>.
 464  
      * @throws SQLException
 465  
      */
 466  
     public Collection getForeignKeys(DatabaseMetaData dbMeta, String tableName)
 467  
         throws SQLException
 468  
     {
 469  0
         Hashtable fks = new Hashtable();
 470  0
         ResultSet foreignKeys = null;
 471  
         try
 472  
         {
 473  0
             foreignKeys = dbMeta.getImportedKeys(null, dbSchema, tableName);
 474  0
             while (foreignKeys.next())
 475  
             {
 476  0
                 String refTableName = foreignKeys.getString(3);
 477  0
                 String fkName = foreignKeys.getString(12);
 478  
                 // if FK has no name - make it up (use tablename instead)
 479  0
                 if (fkName == null)
 480  
                 {
 481  0
                     fkName = refTableName;
 482  
                 }
 483  0
                 Object[] fk = (Object[]) fks.get(fkName);
 484  
                 List refs;
 485  0
                 if (fk == null)
 486  
                 {
 487  0
                     fk = new Object[2];
 488  0
                     fk[0] = refTableName; //referenced table name
 489  0
                     refs = new ArrayList();
 490  0
                     fk[1] = refs;
 491  0
                     fks.put(fkName, fk);
 492  
                 }
 493  
                 else
 494  
                 {
 495  0
                     refs = (ArrayList) fk[1];
 496  
                 }
 497  0
                 String[] ref = new String[2];
 498  0
                 ref[0] = foreignKeys.getString(8); //local column
 499  0
                 ref[1] = foreignKeys.getString(4); //foreign column
 500  0
                 refs.add(ref);
 501  
             }
 502  
         }
 503  
         finally
 504  
         {
 505  0
             if (foreignKeys != null)
 506  
             {
 507  0
                 foreignKeys.close();
 508  
             }
 509  
         }
 510  0
         return fks.values();
 511  
     }
 512  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.