Coverage report

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

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

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