View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2005, DbUnit.org
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   */
21  package org.dbunit.database.search;
22  
23  import java.sql.SQLException;
24  import java.util.Set;
25  
26  import org.apache.commons.collections.set.ListOrderedSet;
27  import org.dbunit.database.IDatabaseConnection;
28  import org.dbunit.database.PrimaryKeyFilter.PkTableMap;
29  import org.dbunit.dataset.DataSetException;
30  import org.dbunit.dataset.FilteredDataSet;
31  import org.dbunit.dataset.IDataSet;
32  import org.dbunit.dataset.filter.ITableFilter;
33  import org.dbunit.util.CollectionsHelper;
34  import org.dbunit.util.search.DepthFirstSearch;
35  import org.dbunit.util.search.SearchException;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  
40  /**
41   * Helper for the graph-search based classes used to calculate dependency
42   * among tables.  
43   * 
44   * @author Felipe Leme (dbunit@felipeal.net)
45   * @author Last changed by: $Author$
46   * @version $Revision$ $Date$
47   * @since Aug 26, 2005
48   */
49  public class TablesDependencyHelper {
50  
51      /**
52       * Logger for this class
53       */
54      private static final Logger logger = LoggerFactory.getLogger(TablesDependencyHelper.class);
55  
56      // this is a "static" class
57      private TablesDependencyHelper() {
58      }
59  
60      /**
61       * Get the name of all tables that depend on the root tables (i.e, all tables that have FKs
62       * pointing to the PK of the root table).
63       * @param connection database connection
64       * @param rootTable root table described above
65       * @return name of all tables that depend on the root table (including the root table), 
66       * in the right order for insertions
67       * @throws SearchException if an exception occurred while calculating the order
68       */
69      public static String[] getDependentTables( IDatabaseConnection connection, String rootTable ) 
70      throws SearchException 
71      {
72          logger.debug("getDependentTables(connection={}, rootTable={}) - start", connection, rootTable);
73          return getDependentTables( connection, new String[] { rootTable } );    
74      }
75  
76      /**
77       * Get the name of all tables that depend on the root tables (i.e, all tables that have FKs
78       * pointing to the PK of one of the root tables).
79       * @param connection database connection
80       * @param rootTables array of root tables described above
81       * @return name of all tables that depend on the root tables (including the root tables), 
82       * in the right order for insertions
83       * @throws SearchException if an exception occurred while calculating the order
84       */
85      public static String[] getDependentTables( IDatabaseConnection connection, String[] rootTables ) 
86      throws SearchException 
87      {
88          logger.debug("getDependentTables(connection={}, rootTables={}) - start", connection, rootTables);
89  
90          ImportedKeysSearchCallback callback = new ImportedKeysSearchCallback(connection);
91          DepthFirstSearch search = new DepthFirstSearch();
92          Set tables = search.search( rootTables, callback );
93          return CollectionsHelper.setToStrings( tables );
94      }
95  
96      /**
97       * Get the name of all tables that the given rootTable depends on (i.e, all tables whose PK is a FK for the root table). 
98       * @param connection database connection
99       * @param rootTable root table described above
100      * @return name of all tables that the rootTable depends on (including the rootTable itself), 
101      * in the right order for insertions
102      * @throws SearchException if an exception occurred while calculating the order
103      * @since 2.4
104      */
105     public static String[] getDependsOnTables( IDatabaseConnection connection, String rootTable ) 
106     throws SearchException 
107     {
108         logger.debug("getDependsOnTables(connection={}, rootTable={}) - start", connection, rootTable);
109 
110         ExportedKeysSearchCallback callback = new ExportedKeysSearchCallback(connection);
111         DepthFirstSearch search = new DepthFirstSearch();
112         Set tables = search.search( new String[]{rootTable}, callback );
113         return CollectionsHelper.setToStrings( tables );
114     }
115 
116     /**
117      * Get the name of all tables that depend on a root table ( i.e, all tables whose PK
118      * is a FK for the root table) and also the tables the root table depends on 
119      * (i.e., all tables which have a FK for the root table's PK). 
120      * @param connection database connection
121      * @param rootTable root table described above
122      * @return name of all tables that depend on the root table (including the root table), 
123      * in the right order for insertions
124      * @throws SearchException if an exception occurred while calculating the order
125      */
126     public static String[] getAllDependentTables( IDatabaseConnection connection, String rootTable ) 
127     throws SearchException 
128     {
129         logger.debug("getAllDependentTables(connection={}, rootTable={}) - start", connection, rootTable);
130         return getAllDependentTables( connection, new String[] { rootTable } );
131     }
132 
133     /**
134      * Get the name of all tables that depend on the root tables ( i.e, all tables whose PK
135      * is a FK for any of the root tables) and also the tables the root tables depends on 
136      * (i.e., all tables which have a FK for any of the root table's PK). 
137      * @param connection database connection
138      * @param rootTables root tables described above
139      * @return name of all tables that depend on the root tables (including the root tables), 
140      * in the right order for insertions
141      * @throws SearchException if an exception occurred while calculating the order
142      */
143     public static String[] getAllDependentTables(IDatabaseConnection connection, String[] rootTables)
144     throws SearchException
145     {
146         logger.debug("getAllDependentTables(connection={}, rootTables={}) - start",connection, rootTables);
147 
148         ImportedAndExportedKeysSearchCallback callback = new ImportedAndExportedKeysSearchCallback(connection);
149         DepthFirstSearch search = new DepthFirstSearch();
150         Set tables = search.search(rootTables, callback);
151         return CollectionsHelper.setToStrings(tables);
152     }
153 
154     // TODO: javadoc (and unit tests) from down here...
155 
156     public static IDataSet getDataset(IDatabaseConnection connection,String rootTable, Set allowedIds) 
157     throws SearchException, SQLException, DataSetException
158     {
159         if (logger.isDebugEnabled())
160         {
161             logger.debug("getDataset(connection={}, rootTable={}, allowedIds={}) - start", 
162                     new Object[] { connection, rootTable, allowedIds });
163         }
164 
165         PkTableMap map = new PkTableMap();
166         map.addAll(rootTable, allowedIds);
167         return getDataset(connection, map);
168     }
169 
170     public static IDataSet getDataset( IDatabaseConnection connection, PkTableMap rootTables ) 
171     throws SearchException, SQLException, DataSetException 
172     {
173         logger.debug("getDataset(connection={}, rootTables={}) - start", connection, rootTables);
174 
175         ImportedKeysSearchCallbackFilteredByPKs callback = new ImportedKeysSearchCallbackFilteredByPKs(connection, rootTables);
176         ITableFilter filter = callback.getFilter();
177         DepthFirstSearch search = new DepthFirstSearch();
178         String[] tableNames = rootTables.getTableNames(); 
179         ListOrderedSet tmpTables = search.search( tableNames, callback );
180         String[] dependentTables  = CollectionsHelper.setToStrings( tmpTables );
181         IDataSet tmpDataset = connection.createDataSet( dependentTables );
182         FilteredDataSet dataset = new FilteredDataSet(filter, tmpDataset);
183         return dataset;
184     }
185 
186     public static IDataSet getAllDataset( IDatabaseConnection connection, String rootTable, Set allowedPKs ) 
187     throws SearchException, SQLException, DataSetException 
188     {
189         if (logger.isDebugEnabled())
190         {
191             logger.debug("getAllDataset(connection={}, rootTable={}, allowedPKs={}) - start", 
192                     new Object[]{ connection, rootTable, allowedPKs });
193         }
194 
195         PkTableMap map = new PkTableMap();
196         map.addAll( rootTable, allowedPKs );
197         return getAllDataset( connection, map );
198     }
199 
200     public static IDataSet getAllDataset( IDatabaseConnection connection, PkTableMap rootTables ) 
201     throws SearchException, SQLException, DataSetException 
202     {
203         logger.debug("getAllDataset(connection={}, rootTables={}) - start", connection, rootTables);
204 
205         ImportedAndExportedKeysSearchCallbackFilteredByPKs callback = new ImportedAndExportedKeysSearchCallbackFilteredByPKs(connection, rootTables);    
206         ITableFilter filter = callback.getFilter();
207         DepthFirstSearch search = new DepthFirstSearch();
208         String[] tableNames = rootTables.getTableNames(); 
209         Set tmpTables = search.search( tableNames, callback );
210         String[] dependentTables  = CollectionsHelper.setToStrings( tmpTables );
211         IDataSet tmpDataset = connection.createDataSet( dependentTables );
212         FilteredDataSet dataset = new FilteredDataSet(filter, tmpDataset);
213         return dataset;
214     }
215 
216     /**
217      * Returns a set of tables on which the given table directly depends on.
218      * @param connection The connection to be used for the database lookup.
219      * @param tableName
220      * @return a set of tables on which the given table directly depends on.
221      * @throws SearchException
222      * @since 2.4
223      */
224     public static Set getDirectDependsOnTables(IDatabaseConnection connection,
225             String tableName) throws SearchException 
226     {
227         logger.debug("getDirectDependsOnTables(connection={}, tableName={}) - start", 
228                     connection, tableName);
229         
230         ExportedKeysSearchCallback callback = new ExportedKeysSearchCallback(connection);
231         // Do a depthFirstSearch with a recursion depth of 1
232         DepthFirstSearch search = new DepthFirstSearch(1);
233         Set tables = search.search( new String[]{tableName}, callback );
234         return tables;
235     }
236 
237     /**
238      * Returns a set of tables which directly depend on the given table.
239      * @param connection The connection to be used for the database lookup.
240      * @param tableName
241      * @return a set of tables on which the given table directly depends on.
242      * @throws SearchException
243      * @since 2.4
244      */
245     public static Set getDirectDependentTables(IDatabaseConnection connection,
246             String tableName) throws SearchException 
247     {
248         logger.debug("getDirectDependentTables(connection={}, tableName={}) - start", 
249                     connection, tableName);
250 
251         ImportedKeysSearchCallback callback = new ImportedKeysSearchCallback(connection);
252         // Do a depthFirstSearch with a recursion depth of 1
253         DepthFirstSearch search = new DepthFirstSearch(1);
254         Set tables = search.search( new String[]{tableName}, callback );
255         return tables;
256     }
257 
258 }