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>© 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 }