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

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