View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2002-2004, 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.dataset;
22  
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  
31  import org.dbunit.database.AmbiguousTableNameException;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /**
36   * Associates a table name with an arbitrary object. Moreover the
37   * order of the added table names is maintained and the ordered table
38   * names can be retrieved via {@link #getTableNames()}.
39   * <p>
40   * The map ensures that one table name can only be added once.
41   * </p>
42   * 
43   * TODO In the future it might be discussed if a ListOrderedMap (apache-commons-collections) can/should be used.
44   * 
45   * @author gommma
46   * @author Last changed by: $Author$
47   * @version $Revision$
48   * @since 2.4.0
49   */
50  public class OrderedTableNameMap
51  {
52      /**
53       * Logger for this class
54       */
55      private static final Logger LOGGER = LoggerFactory.getLogger(OrderedTableNameMap.class);
56  
57  	/**
58  	 * The map for fast access to the existing table names and for
59  	 * associating an arbitrary object with a table name
60  	 */
61  	private Map _tableMap = new HashMap();
62  	/**
63  	 * Chronologically ordered list of table names - keeps the order
64  	 * in which the table names have been added as well as the case in
65  	 * which the table has been added
66  	 */
67  	private List _tableNames = new ArrayList();
68  	
69  	private String _lastTableNameOverride;
70  	
71  	/**
72  	 * Whether or not case sensitive table names should be used. Defaults to false.
73  	 */
74  	private boolean _caseSensitiveTableNames = false;
75  	
76  	
77  	/**
78       * Creates a new map which does strictly force that one table can only occur once.
79       * @param caseSensitiveTableNames Whether or not table names should be case sensitive
80       */
81      public OrderedTableNameMap(boolean caseSensitiveTableNames)
82      {
83          _caseSensitiveTableNames = caseSensitiveTableNames;
84      }
85  
86  	/**
87  	 * Returns the object associated with the given table name
88  	 * @param tableName The table name for which the associated object is retrieved
89  	 * @return The object that has been associated with the given table name
90  	 */
91  	public Object get(String tableName) 
92  	{
93  	    String correctedCaseTableName = this.getTableName(tableName);
94  		return this._tableMap.get(correctedCaseTableName);
95  	}
96  
97  
98  	/**
99  	 * Provides the ordered table names having the same order in which the table
100 	 * names have been added via {@link #add(String, Object)}.
101 	 * @return The list of table names ordered in the sequence as
102 	 * they have been added to this map
103 	 */
104 	public String[] getTableNames() 
105 	{
106 		return (String[])this._tableNames.toArray(new String[0]);
107 	}
108 
109 	/**
110 	 * Checks if this map contains the given table name
111 	 * @param tableName
112 	 * @return Returns <code>true</code> if the map of tables contains the given table name
113 	 */
114 	public boolean containsTable(String tableName) 
115 	{
116 	    String correctedCaseTableName = this.getTableName(tableName);
117 		return _tableMap.containsKey(correctedCaseTableName);
118 	}
119 
120     /**
121      * @param tableName The table name to check
122      * @return <code>true</code> if the given tableName matches the last table that has been added to this map.
123      */
124     public boolean isLastTable(String tableName) 
125     {
126         if(LOGGER.isDebugEnabled())
127             LOGGER.debug("isLastTable(tableName={}) - start", tableName);
128         
129         if(this._tableNames.size() == 0)
130         {
131             return false;
132         }
133         else 
134         {
135             String lastTable = getLastTableName();
136             String lastTableCorrectCase = this.getTableName(lastTable);
137             String inputTableCorrectCase = this.getTableName(tableName);
138             return lastTableCorrectCase.equals(inputTableCorrectCase);
139         }
140     }
141 
142     /**
143      * @return The name of the last table that has been added to this map. Returns <code>null</code> if no 
144      * table has been added yet.
145      */
146     public String getLastTableName()
147     {
148         if(LOGGER.isDebugEnabled())
149             LOGGER.debug("getLastTableName() - start");
150         
151         if(_lastTableNameOverride != null)
152         {
153             return _lastTableNameOverride;
154         }
155         
156         if(_tableNames.size()>0)
157         {
158             String lastTable = (String) _tableNames.get(this._tableNames.size()-1);
159             return lastTable;
160         }
161         else
162         {
163             return null;
164         }
165     }
166     
167 
168     public void setLastTable(String tableName) throws NoSuchTableException 
169     {
170         if(LOGGER.isDebugEnabled())
171             LOGGER.debug("setLastTable(name{}) - start", tableName);
172         
173         if(!this.containsTable(tableName))
174         {
175             throw new NoSuchTableException(tableName);
176         }
177         
178         this._lastTableNameOverride = tableName;
179     }
180 
181 	/**
182 	 * Adds the given table name to the map of table names, associating 
183 	 * it with the given object.
184 	 * @param tableName The table name to be added
185 	 * @param object Object to be associated with the given table name. Can be null
186 	 * @throws AmbiguousTableNameException If the given table name already exists
187 	 */
188 	public void add(String tableName, Object object) throws AmbiguousTableNameException 
189 	{
190         if(LOGGER.isDebugEnabled())
191             LOGGER.debug("add(tableName={}, object={}) - start", tableName, object);
192 	    
193 	    // Get the table name in the correct case
194         String tableNameCorrectedCase = this.getTableName(tableName);
195         // prevent table name conflict
196         if (this.containsTable(tableNameCorrectedCase))
197         {
198             throw new AmbiguousTableNameException(tableNameCorrectedCase);
199         }
200         else {
201             this._tableMap.put(tableNameCorrectedCase, object);
202             this._tableNames.add(tableName);
203             // Reset the override of the lastTableName
204             this._lastTableNameOverride = null;
205         }
206 	}
207 	
208     /**
209      * @return The values of this map ordered in the sequence they have been added
210      */
211     public Collection orderedValues() 
212     {
213         if(LOGGER.isDebugEnabled())
214             LOGGER.debug("orderedValues() - start");
215 
216         List orderedValues = new ArrayList(this._tableNames.size());
217         for (Iterator iterator = _tableNames.iterator(); iterator.hasNext();) {
218             String tableName = (String) iterator.next();
219             Object object = this.get(tableName);
220             orderedValues.add(object);
221         }
222         return orderedValues;
223     }
224     
225 	/**
226 	 * Updates the value associated with the given table name. Must be invoked if
227 	 * the table name has already been added before.
228 	 * @param tableName The table name for which the association should be updated
229 	 * @param object The new object to be associated with the given table name
230 	 */
231 	public void update(String tableName, Object object) 
232 	{
233         if(LOGGER.isDebugEnabled())
234             LOGGER.debug("update(tableName={}, object={}) - start", tableName, object);
235 
236         // prevent table name conflict
237         if (!this.containsTable(tableName))
238         {
239         	throw new IllegalArgumentException("The table name '" + tableName + "' does not exist in the map");
240         }
241         tableName = this.getTableName(tableName);
242         this._tableMap.put(tableName, object);
243 	}
244 
245     /**
246      * Returns the table name in the correct case (for example as upper case string)
247      * @param tableName The input table name to be resolved
248      * @return The table name for the given string in the correct case.
249      */
250     public String getTableName(String tableName) 
251     {
252         if(LOGGER.isDebugEnabled())
253             LOGGER.debug("getTableName(tableName={}) - start", tableName);
254         
255         String result = tableName;
256         if(!_caseSensitiveTableNames)
257         {
258             // "Locale.ENGLISH" Fixes bug #1537894 when clients have a special
259             // locale like turkish. (for release 2.4.3)
260             result = tableName.toUpperCase(Locale.ENGLISH);
261         }
262 
263         if(LOGGER.isDebugEnabled())
264             LOGGER.debug("getTableName(tableName={}) - end - result={}", tableName, result);
265         
266         return result;
267     }
268 
269 	public String toString()
270 	{
271 		StringBuffer sb = new StringBuffer();
272 		sb.append(getClass().getName()).append("[");
273 		sb.append("_tableNames=").append(_tableNames);
274 		sb.append(", _tableMap=").append(_tableMap);
275 		sb.append(", _caseSensitiveTableNames=").append(_caseSensitiveTableNames);
276 		sb.append("]");
277 		return sb.toString();
278 	}
279 	
280 }