Coverage report

  %line %branch
com.workingdogs.village.Schema
0% 
0% 

 1  
 package com.workingdogs.village;
 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.ByteArrayOutputStream;
 23  
 import java.io.PrintWriter;
 24  
 
 25  
 import java.sql.Connection;
 26  
 import java.sql.ResultSet;
 27  
 import java.sql.ResultSetMetaData;
 28  
 import java.sql.SQLException;
 29  
 import java.sql.Statement;
 30  
 
 31  
 import java.util.Enumeration;
 32  
 import java.util.Hashtable;
 33  
 
 34  
 /**
 35  
  * The Schema object represents the <a href="Column.html">Columns</a> in a database table. It contains a collection of <a
 36  
  * href="Column.html">Column</a> objects.
 37  
  *
 38  
  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
 39  
  * @author John D. McNally
 40  
  * @version $Revision: 568 $
 41  
  */
 42  
 public final class Schema
 43  
 {
 44  
     /** TODO: DOCUMENT ME! */
 45  
     private String tableName;
 46  
 
 47  
     /** TODO: DOCUMENT ME! */
 48  
     private String columnsAttribute;
 49  
 
 50  
     /** TODO: DOCUMENT ME! */
 51  
     private int numberOfColumns;
 52  
 
 53  
     /** TODO: DOCUMENT ME! */
 54  
     private Column [] columns;
 55  
 
 56  
     /** TODO: DOCUMENT ME! */
 57  0
     private static Hashtable schemaCache = new Hashtable();
 58  
 
 59  
     /**
 60  
      * This attribute is used to complement columns in the event that this schema represents more than one table.  Its keys are
 61  
      * String contains table names and its elements are Hashtables containing columns.
 62  
      */
 63  0
     private Hashtable tableHash = null;
 64  
 
 65  
     /** TODO: DOCUMENT ME! */
 66  0
     private boolean singleTable = true;
 67  
 
 68  
     /**
 69  
      * A blank Schema object
 70  
      */
 71  
     public Schema()
 72  0
     {
 73  0
         this.tableName = "";
 74  0
         this.columnsAttribute = null;
 75  0
         this.numberOfColumns = 0;
 76  0
     }
 77  
 
 78  
     /**
 79  
      * Creates a Schema with all columns
 80  
      *
 81  
      * @param conn
 82  
      * @param tableName
 83  
      *
 84  
      * @return an instance of myself
 85  
      *
 86  
      * @exception SQLException
 87  
      * @exception DataSetException
 88  
      */
 89  
     public Schema schema(Connection conn, String tableName)
 90  
             throws SQLException, DataSetException
 91  
     {
 92  0
         return schema(conn, tableName, "*");
 93  
     }
 94  
 
 95  
     /**
 96  
      * Creates a Schema with the named columns in the columnsAttribute
 97  
      *
 98  
      * @param conn
 99  
      * @param tableName
 100  
      * @param columnsAttribute
 101  
      *
 102  
      * @return an instance of myself
 103  
      *
 104  
      * @exception SQLException
 105  
      * @exception DataSetException
 106  
      */
 107  
     public synchronized Schema schema(Connection conn, String tableName, String columnsAttribute)
 108  
             throws SQLException, DataSetException
 109  
     {
 110  0
         if (columnsAttribute == null)
 111  
         {
 112  0
             columnsAttribute = "*";
 113  
         }
 114  
 
 115  0
         Statement stmt = null;
 116  
 
 117  
         try
 118  
         {
 119  0
             String keyValue = conn.getMetaData().getURL() + tableName;
 120  0
             Schema tableSchema = (Schema) schemaCache.get(keyValue);
 121  
 
 122  0
             if (tableSchema == null)
 123  
             {
 124  0
                 String sql = "SELECT " + columnsAttribute + " FROM " + tableName + " WHERE 1 = -1";
 125  0
                 stmt = conn.createStatement();
 126  
 
 127  0
                 ResultSet rs = stmt.executeQuery(sql);
 128  
 
 129  0
                 if (rs != null)
 130  
                 {
 131  0
                     tableSchema = new Schema();
 132  0
                     tableSchema.setTableName(tableName);
 133  0
                     tableSchema.setAttributes(columnsAttribute);
 134  0
                     tableSchema.populate(rs.getMetaData(), tableName);
 135  0
                     schemaCache.put(keyValue, tableSchema);
 136  
                 }
 137  
                 else
 138  
                 {
 139  0
                     throw new DataSetException("Couldn't retrieve schema for " + tableName);
 140  
                 }
 141  
             }
 142  
 
 143  0
             return tableSchema;
 144  
         }
 145  
         finally
 146  
         {
 147  0
             if (stmt != null)
 148  
             {
 149  0
                 stmt.close();
 150  
             }
 151  
         }
 152  
     }
 153  
 
 154  
     /**
 155  
      * Appends data to the tableName that this schema was first created with.
 156  
      *
 157  
      * <P></p>
 158  
      *
 159  
      * @param app String to append to tableName
 160  
      *
 161  
      * @see TableDataSet#tableQualifier(java.lang.String)
 162  
      */
 163  
     void appendTableName(String app)
 164  
     {
 165  0
         this.tableName = class="keyword">this.tableName + " " + app;
 166  0
     }
 167  
 
 168  
     /**
 169  
      * List of columns to select from the table
 170  
      *
 171  
      * @return the list of columns to select from the table
 172  
      */
 173  
     public String attributes()
 174  
     {
 175  0
         return this.columnsAttribute;
 176  
     }
 177  
 
 178  
     /**
 179  
      * Returns the requested Column object at index i
 180  
      *
 181  
      * @param i
 182  
      *
 183  
      * @return the requested column
 184  
      *
 185  
      * @exception DataSetException
 186  
      */
 187  
     public Column column(int i)
 188  
             throws DataSetException
 189  
     {
 190  0
         if (i == 0)
 191  
         {
 192  0
             throw new DataSetException("Columns are 1 based");
 193  
         }
 194  0
         else if (i > numberOfColumns)
 195  
         {
 196  0
             throw new DataSetException("There are only " + numberOfColumns() + " available!");
 197  
         }
 198  
 
 199  
         try
 200  
         {
 201  0
             return columns[i];
 202  
         }
 203  0
         catch (Exception e)
 204  
         {
 205  0
             throw new DataSetException("Column number: " + numberOfColumns() + " does not exist!");
 206  
         }
 207  
     }
 208  
 
 209  
     /**
 210  
      * Returns the requested Column object by name
 211  
      *
 212  
      * @param colName
 213  
      *
 214  
      * @return the requested column
 215  
      *
 216  
      * @exception DataSetException
 217  
      */
 218  
     public Column column(String colName)
 219  
             throws DataSetException
 220  
     {
 221  0
         return column(index(colName));
 222  
     }
 223  
 
 224  
     /**
 225  
      * Returns the requested Column object by name
 226  
      *
 227  
      * @param colName
 228  
      *
 229  
      * @return the requested column
 230  
      *
 231  
      * @exception DataSetException
 232  
      */
 233  
     public Column getColumn(String colName)
 234  
             throws DataSetException
 235  
     {
 236  0
         int dot = colName.indexOf('.');
 237  
 
 238  0
         if (dot > 0)
 239  
         {
 240  0
             String table = colName.substring(0, dot);
 241  0
             String col = colName.substring(dot + 1);
 242  
 
 243  0
             return getColumn(table, col);
 244  
         }
 245  
 
 246  0
         return column(index(colName));
 247  
     }
 248  
 
 249  
     /**
 250  
      * Returns the requested Column object belonging to the specified table by name
 251  
      *
 252  
      * @param tableName
 253  
      * @param colName
 254  
      *
 255  
      * @return the requested column, null if a column by the specified name does not exist.
 256  
      *
 257  
      * @exception DataSetException
 258  
      */
 259  
     public Column getColumn(String tableName, String colName)
 260  
             throws DataSetException
 261  
     {
 262  0
         return (Column) ((Hashtable) tableHash.get(tableName)).get(colName);
 263  
     }
 264  
 
 265  
     /**
 266  
      * Returns an array of columns
 267  
      *
 268  
      * @return an array of columns
 269  
      */
 270  
     Column [] getColumns()
 271  
     {
 272  0
         return this.columns;
 273  
     }
 274  
 
 275  
     /**
 276  
      * returns the table name that this Schema represents
 277  
      *
 278  
      * @return the table name that this Schema represents
 279  
      *
 280  
      * @throws DataSetException TODO: DOCUMENT ME!
 281  
      */
 282  
     public String getTableName()
 283  
             throws DataSetException
 284  
     {
 285  0
         if (singleTable)
 286  
         {
 287  0
             return tableName;
 288  
         }
 289  
         else
 290  
         {
 291  0
             throw new DataSetException("This schema represents several tables.");
 292  
         }
 293  
     }
 294  
 
 295  
     /**
 296  
      * returns all table names that this Schema represents
 297  
      *
 298  
      * @return the table names that this Schema represents
 299  
      */
 300  
     public String [] getAllTableNames()
 301  
     {
 302  0
         Enumeration e = tableHash.keys();
 303  0
         String [] tableNames = new String[tableHash.size()];
 304  
 
 305  0
         for (int i = 0; e.hasMoreElements(); i++)
 306  
         {
 307  0
             tableNames[i] = (String) e.nextElement();
 308  
         }
 309  
 
 310  0
         return tableNames;
 311  
     }
 312  
 
 313  
     /**
 314  
      * Gets the index position of a named column.  If multiple tables are represented and they have columns with the same name,
 315  
      * this method returns the first one listed, if the table name is not specified.
 316  
      *
 317  
      * @param colName
 318  
      *
 319  
      * @return the requested column index integer
 320  
      *
 321  
      * @exception DataSetException
 322  
      */
 323  
     public int index(String colName)
 324  
             throws DataSetException
 325  
     {
 326  0
         int dot = colName.indexOf('.');
 327  
 
 328  0
         if (dot > 0)
 329  
         {
 330  0
             String table = colName.substring(0, dot);
 331  0
             String col = colName.substring(dot + 1);
 332  
 
 333  0
             return index(table, col);
 334  
         }
 335  
 
 336  0
         for (int i = 1; i <= numberOfColumns(); i++)
 337  
         {
 338  0
             if (columns[i].name().equalsIgnoreCase(colName))
 339  
             {
 340  0
                 return i;
 341  
             }
 342  
         }
 343  
 
 344  0
         throw new DataSetException("Column name: " + colName + " does not exist!");
 345  
     }
 346  
 
 347  
     /**
 348  
      * Gets the index position of a named column.
 349  
      *
 350  
      * @param tableName
 351  
      * @param colName
 352  
      *
 353  
      * @return the requested column index integer
 354  
      *
 355  
      * @exception DataSetException
 356  
      */
 357  
     public int index(String tableName, String colName)
 358  
             throws DataSetException
 359  
     {
 360  0
         for (int i = 1; i <= numberOfColumns(); i++)
 361  
         {
 362  0
             if (columns[i].name().equalsIgnoreCase(colName) && columns[i].getTableName().equalsIgnoreCase(tableName))
 363  
             {
 364  0
                 return i;
 365  
             }
 366  
         }
 367  
 
 368  0
         throw new DataSetException("Column name: " + colName + " does not exist!");
 369  
     }
 370  
 
 371  
     /**
 372  
      * Checks to see if this DataSet represents one table in the database.
 373  
      *
 374  
      * @return true if only one table is represented, false otherwise.
 375  
      */
 376  
     public boolean isSingleTable()
 377  
     {
 378  0
         return singleTable;
 379  
     }
 380  
 
 381  
     /**
 382  
      * Gets the number of columns in this Schema
 383  
      *
 384  
      * @return integer number of columns
 385  
      */
 386  
     public int numberOfColumns()
 387  
     {
 388  0
         return this.numberOfColumns;
 389  
     }
 390  
 
 391  
     /**
 392  
      * Internal method which populates this Schema object with Columns.
 393  
      *
 394  
      * @param meta The meta data of the ResultSet used to build this Schema.
 395  
      * @param tableName The name of the table referenced in this schema, or null if unknown or multiple tables are involved.
 396  
      *
 397  
      * @exception SQLException
 398  
      * @exception DataSetException
 399  
      */
 400  
     void populate(ResultSetMetaData meta, String tableName)
 401  
             throws SQLException, DataSetException
 402  
     {
 403  0
         this.numberOfColumns = meta.getColumnCount();
 404  0
         columns = new Column[numberOfColumns() + 1];
 405  
 
 406  0
         for (int i = 1; i <= numberOfColumns(); i++)
 407  
         {
 408  0
             Column col = new Column();
 409  0
             col.populate(meta, i, tableName);
 410  0
             columns[i] = col;
 411  
 
 412  0
             if ((i > 1) && !col.getTableName().equalsIgnoreCase(columns[i - 1].getTableName()))
 413  
             {
 414  0
                 singleTable = false;
 415  
             }
 416  
         }
 417  
 
 418  
         // Avoid creating a Hashtable in the most common case where only one
 419  
         // table is involved, even though this makes the multiple table case
 420  
         // more expensive because the table/column info is duplicated.
 421  0
         if (singleTable)
 422  
         {
 423  
             // If available, use a the caller supplied table name.
 424  0
             if ((tableName != null) && (tableName.length() > 0))
 425  
             {
 426  0
                 setTableName(tableName);
 427  
             }
 428  
             else
 429  
             {
 430  
                 // Since there's only one table involved, attempt to set the
 431  
                 // table name to that of the first column.  Sybase jConnect
 432  
                 // 5.2 and older will fail, in which case we are screwed.
 433  
                 try
 434  
                 {
 435  0
                     setTableName(meta.getTableName(1));
 436  
                 }
 437  0
                 catch (Exception e)
 438  
                 {
 439  0
                     setTableName("");
 440  0
                 }
 441  
             }
 442  
         }
 443  
         else
 444  
         {
 445  0
             tableHash = new Hashtable((int) ((1.25 * numberOfColumns) + 1));
 446  
 
 447  0
             for (int i = 1; i <= numberOfColumns(); i++)
 448  
             {
 449  0
                 if (tableHash.containsKey(columns[i].getTableName()))
 450  
                 {
 451  0
                     ((Hashtable) tableHash.get(columns[i].getTableName())).put(columns[i].name(), columns[i]);
 452  
                 }
 453  
                 else
 454  
                 {
 455  0
                     Hashtable columnHash = new Hashtable((int) ((1.25 * numberOfColumns) + 1));
 456  0
                     columnHash.put(columns[i].name(), columns[i]);
 457  0
                     tableHash.put(columns[i].getTableName(), columnHash);
 458  
                 }
 459  
             }
 460  
         }
 461  0
     }
 462  
 
 463  
     /**
 464  
      * Sets the columns to select from the table
 465  
      *
 466  
      * @param attributes comma separated list of column names
 467  
      */
 468  
     void setAttributes(String attributes)
 469  
     {
 470  0
         this.columnsAttribute = attributes;
 471  0
     }
 472  
 
 473  
     /**
 474  
      * Sets the table name that this Schema represents
 475  
      *
 476  
      * @param tableName
 477  
      */
 478  
     void setTableName(String tableName)
 479  
     {
 480  0
         this.tableName = tableName;
 481  0
     }
 482  
 
 483  
     /**
 484  
      * returns the table name that this Schema represents
 485  
      *
 486  
      * @return the table name that this Schema represents
 487  
      *
 488  
      * @throws DataSetException TODO: DOCUMENT ME!
 489  
      */
 490  
     public String tableName()
 491  
             throws DataSetException
 492  
     {
 493  0
         return getTableName();
 494  
     }
 495  
 
 496  
     /**
 497  
      * This returns a representation of this Schema
 498  
      *
 499  
      * @return a string
 500  
      */
 501  
     public String toString()
 502  
     {
 503  0
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
 504  0
         PrintWriter out = new PrintWriter(bout);
 505  0
         out.print('{');
 506  
 
 507  0
         for (int i = 1; i <= numberOfColumns; i++)
 508  
         {
 509  0
             out.print('\'');
 510  
 
 511  0
             if (!singleTable)
 512  
             {
 513  0
                 out.print(columns[i].getTableName() + '.');
 514  
             }
 515  
 
 516  0
             out.print(columns[i].name() + '\'');
 517  
 
 518  0
             if (i < numberOfColumns)
 519  
             {
 520  0
                 out.print(',');
 521  
             }
 522  
         }
 523  
 
 524  0
         out.print('}');
 525  0
         out.flush();
 526  
 
 527  0
         return bout.toString();
 528  
     }
 529  
 }

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