001    package com.sptci.rwt;
002    
003    import java.sql.Connection;
004    import java.sql.DatabaseMetaData;
005    import java.sql.ResultSet;
006    import java.sql.SQLException;
007    
008    import java.util.ArrayList;
009    import java.util.Collection;
010    import java.util.Map;
011    import java.util.LinkedHashMap;
012    import java.util.TreeMap;
013    
014    import com.sptci.util.CloseJDBCResources;
015    
016    /**
017     * An analyser for analysing foreign key columns for tables in the database.
018     *
019     * <p>&copy; Copyright 2007 <a href='http://sptci.com/' target='_new'>Sans Pareil Technologies, Inc.</a></p>
020     * @author Rakesh Vidyadharan 2007-09-25
021     * @version $Id: ForeignKeyAnalyser.java 4123 2008-05-25 21:49:01Z rakesh $
022     * @see java.sql.DatabaseMetaData#getImportedKeys
023     */
024    public class ForeignKeyAnalyser extends KeyAnalyser
025    {
026      /**
027       * Create a new instance of the class using the specified connection
028       * manager.
029       *
030       * @param manager The manager for obtaining database connections.
031       */
032      public ForeignKeyAnalyser( final ConnectionManager manager )
033      {
034        super( manager );
035      }
036    
037      /**
038       * Returns a collection of {@link ForeignKeyMetaData} objects that
039       * contain all information pertaining to the foreign keys for the
040       * specified table.
041       *
042       * @see Analyser#analyse
043       * @see #getNames
044       * @param parameters Must contain two parameters which are the names of
045       *   the <code>catalog/schema</code> and table from which foreign key
046       *   metadata are to be retrieved.
047       */
048      @Override
049      public Collection<ForeignKeyMetaData> analyse(
050          final MetaData... parameters ) throws SQLException
051      {
052        Connection connection = null;
053        ResultSet resultSet = null;
054        final Map<String,ForeignKeyMetaData> md =
055          new TreeMap<String,ForeignKeyMetaData>();
056    
057        try
058        {
059          final CatalogueSchema cs = getNames( parameters[0] );
060          final TableMetaData tmd = (TableMetaData) parameters[1];
061    
062          connection = manager.open();
063          final DatabaseMetaData dmd = connection.getMetaData();
064          resultSet = dmd.getImportedKeys(
065              cs.getCatalogue(), cs.getSchema(), tmd.getName() );
066          
067          boolean first = true;
068          while ( resultSet.next() )
069          {
070            if ( first )
071            {
072              checkTableColumns( tmd );
073              first = false;
074            }
075    
076            final String name = resultSet.getString( "fk_name" );
077    
078            ForeignKeyMetaData fkmd = md.get( name );
079            if ( fkmd == null )
080            {
081              fkmd = new ForeignKeyMetaData();
082    
083              fkmd.setName( name );
084              fkmd.setReferencedSchema( resultSet.getString( "pktable_schem" ) );
085              fkmd.setReferencedTable( resultSet.getString( "pktable_name" ) );
086    
087              fkmd.setUpdateRule(
088                  processRule( resultSet.getShort( "update_rule" ) ) );
089              fkmd.setDeleteRule(
090                  processRule( resultSet.getShort( "delete_rule" ) ) );
091              fkmd.setDeferrability(
092                  processDeferrability( resultSet.getShort( "deferrability" ) ) );
093    
094              fkmd.setTable( tmd );
095              md.put( name, fkmd );
096            }
097    
098            fkmd.addColumn(
099                tmd.getColumn( resultSet.getString( "fkcolumn_name" ) ),
100                resultSet.getString( "pkcolumn_name" ) );
101          }
102    
103          tmd.addForeignKeys( md.values() );
104        }
105        finally
106        {
107          CloseJDBCResources.close( resultSet );
108          CloseJDBCResources.close( connection );
109        }
110    
111        return md.values();
112      }
113    
114      /**
115       * Process the <code>update_rule/delete_rule</code> values and match
116       * them with the appropriate {@link ForeignKeyMetaData.Rule} value.
117       *
118       * @param value The the short value read from result set.
119       * @return The appropriate rule value.
120       */
121      protected ForeignKeyMetaData.Rule processRule( final short value )
122      {
123        ForeignKeyMetaData.Rule rule = null;
124    
125        switch ( value )
126        {
127          case DatabaseMetaData.importedKeyNoAction :
128            rule = ForeignKeyMetaData.Rule.NoAction;
129            break;
130          case DatabaseMetaData.importedKeyCascade :
131            rule = ForeignKeyMetaData.Rule.Cascade;
132            break;
133          case DatabaseMetaData.importedKeySetNull :
134            rule = ForeignKeyMetaData.Rule.SetNull;
135            break;
136          case DatabaseMetaData.importedKeySetDefault :
137            rule = ForeignKeyMetaData.Rule.SetDefault;
138            break;
139          case DatabaseMetaData.importedKeyRestrict :
140            rule = ForeignKeyMetaData.Rule.Restrict;
141            break;
142        };
143    
144        return rule;
145      }
146    
147      /**
148       * Process the <code>deferrability</code> value and match them with the
149       * appropriate {@link ForeignKeyMetaData.Deferrability} value.
150       *
151       * @param value The the short value read from result set.
152       * @return The appropriate deferrability value.
153       */
154      protected ForeignKeyMetaData.Deferrability processDeferrability(
155          final short value )
156      {
157        ForeignKeyMetaData.Deferrability deferrability = null;
158    
159        switch ( value )
160        {
161          case DatabaseMetaData.importedKeyInitiallyDeferred :
162            deferrability = ForeignKeyMetaData.Deferrability.InitiallyDeferred;
163            break;
164          case DatabaseMetaData.importedKeyInitiallyImmediate :
165            deferrability = ForeignKeyMetaData.Deferrability.InitiallyImmediate;
166            break;
167          case DatabaseMetaData.importedKeyNotDeferrable :
168            deferrability = ForeignKeyMetaData.Deferrability.NotDeferrable;
169            break;
170        };
171    
172        return deferrability;
173      }
174    }