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 final StringBuilder sb = new StringBuilder();
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 }