View Javadoc

1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2004-2008, 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.util;
22  
23  import org.dbunit.DatabaseUnitRuntimeException;
24  import org.dbunit.database.DatabaseConfig;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  /**
29   * Utility to parse a fully qualified table name into its components <i>schema</i> and <i>table</i>.
30   * @author gommma
31   * @author Last changed by: $Author$
32   * @version $Revision$ $Date$
33   * @since 2.3.0
34   */
35  public class QualifiedTableName
36  {
37      /**
38       * Logger for this class
39       */
40      private static final Logger logger = LoggerFactory.getLogger(QualifiedTableName.class);
41  
42  	private String schema;
43  	private String table;
44  	private String escapePattern;
45  	
46  	/**
47  	 * Creates an object parsing the given tableName.
48  	 * @param tableName The table name, either qualified or unqualified. If it is qualified (like "MYSCHEMA.MYTABLE")
49  	 * this schema name has precedence before the given <code>defaultSchema</code> parameter.
50  	 * @param defaultSchema The schema that is used when the given tableName is not fully qualified
51  	 * (i.e. it is not like "MYSCHEMA.MYTABLE"). Can be null
52  	 */
53  	public QualifiedTableName(String tableName, String defaultSchema)
54  	{
55  		this(tableName, defaultSchema, null);
56  	}
57  	
58  	/**
59  	 * Creates an object parsing the given tableName.
60  	 * @param tableName The table name, either qualified or unqualified. If it is qualified (like "MYSCHEMA.MYTABLE")
61  	 * this schema name has precedence before the given <code>defaultSchema</code> parameter.
62  	 * @param defaultSchema The schema that is used when the given tableName is not fully qualified
63  	 * (i.e. it is not like "MYSCHEMA.MYTABLE"). Can be null
64       * @param escapePattern The escape pattern to be applied on the prefix and the name. Can be null.
65  	 */
66  	public QualifiedTableName(String tableName, String defaultSchema, String escapePattern)
67  	{
68  		if(tableName==null){
69  			throw new NullPointerException("The parameter 'tableName' must not be null");
70  		}
71      	parseFullTableName(tableName, defaultSchema);
72      	this.escapePattern = escapePattern;
73  	}
74  
75  	/**
76  	 * Parses the given full table name into a schema name and a table name if available. If
77  	 * no schema is set the value of the {@link #getSchema()} is null.
78  	 * Sets the corresponding members of this class if found.
79  	 * @param fullTableName potentially fully qualified table name
80  	 * @param defaultSchema The schema that is used when the given tableName is not fully qualified
81  	 * (i.e. it is not like "MYSCHEMA.MYTABLE"). Can be null
82  	 */
83  	private void parseFullTableName(String fullTableName, String defaultSchema)
84  	{
85  		if(fullTableName==null){
86  			throw new NullPointerException("The parameter 'fullTableName' must not be null");
87  		}
88          // check if a schema is in front
89  		int firstDotIndex = fullTableName.indexOf(".");
90          if (firstDotIndex != -1) {
91              // set schema
92          	this.schema = fullTableName.substring(0, firstDotIndex);
93              // set table name without schema
94          	this.table = fullTableName.substring(firstDotIndex + 1);
95          }
96          else 
97          {
98          	// No schema name found in table
99          	this.table = fullTableName;
100         	// If the schema has not been found in the given table name 
101         	// (that means there is no "MYSCHEMA.MYTABLE" but only a "MYTABLE")
102         	// then set the schema to the given default schema
103     		this.schema = defaultSchema;
104         }
105 	}
106 
107 	/**
108 	 * @return The schema name which can be null if no schema has been given in the constructor
109 	 */
110 	public String getSchema() {
111 		return schema;
112 	}
113 
114 	/**
115 	 * @return The name of the plain, unqualified table
116 	 */
117 	public String getTable() {
118 		return table;
119 	}
120 
121 	/**
122 	 * @return The qualified table name with the prepended schema if a schema is available
123 	 */
124 	public String getQualifiedName() 
125 	{
126 		logger.debug("getQualifiedName() - start");
127 		
128 		return getQualifiedName(this.schema, this.table, this.escapePattern);
129 	}
130 
131 	/**
132 	 * Returns the qualified name using the values given in the constructor.
133 	 * The qualified table name is <b>only</b> returned if the feature
134 	 * {@link DatabaseConfig#FEATURE_QUALIFIED_TABLE_NAMES} is set. Otherwise the given
135 	 * name is returned unqualified (i.e. without prepending the prefix/schema).
136 	 * @return The qualified table name with the prepended schema if a schema is available.
137 	 * The qualified table name is <b>only</b> returned if the feature 
138 	 * {@link DatabaseConfig#FEATURE_QUALIFIED_TABLE_NAMES} is set in the given <code>config</code>.
139 	 */
140 	public String getQualifiedNameIfEnabled(DatabaseConfig config) 
141 	{
142 		logger.debug("getQualifiedNameIfEnabled(config={}) - start", config);
143 
144         boolean feature = config.getFeature(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES);
145         if (feature)
146         {
147         	logger.debug("Qualified table names feature is enabled. Returning qualified table name");
148             return getQualifiedName(this.schema, this.table, this.escapePattern);
149         }
150         else 
151         {
152         	logger.debug("Qualified table names feature is disabled. Returning plain table name");
153 //        	return this.table;
154         	return getQualifiedName(null, this.table, this.escapePattern);
155         }
156 	}
157 
158 	public String toString() {
159 		StringBuffer sb = new StringBuffer();
160 		sb.append(getClass().getName()).append("[");
161 		sb.append("schema=").append(schema);
162 		sb.append(", table=").append(table);
163 		sb.append("]");
164 		return sb.toString();
165 	}
166 	
167 	
168 	
169     /**
170      * Returns the specified name qualified with the specified prefix. The name
171      * is not modified if the prefix is <code>null</code> or if the name is
172      * already qualified.
173      * <p>
174      * Example: <br>
175      * <code>getQualifiedName(null, "NAME")</code> returns
176      * <code>"NAME"</code>. <code>getQualifiedName("PREFIX", "NAME")</code>
177      * returns <code>"PREFIX.NAME"</code> and
178      * <code>getQualifiedName("PREFIX2", "PREFIX1.NAME")</code>
179      * returns <code>"PREFIX1.NAME"</code>.
180      * 
181      * @param prefix the prefix that qualifies the name and is prepended if the name is not qualified yet
182      * @param name the name The name to be qualified if it is not qualified already
183      * @param escapePattern The escape pattern to be applied on the prefix and the name. Can be null.
184      * @return The qualified name
185      */
186     private String getQualifiedName(String prefix, String name,
187             String escapePattern)
188     {
189         if(logger.isDebugEnabled())
190             logger.debug("getQualifiedName(prefix={}, name={}, escapePattern={}) - start", 
191                     new String[] {prefix, name, escapePattern});
192 
193         if (escapePattern != null)
194         {
195             prefix = getEscapedName(prefix, escapePattern);
196             name = getEscapedName(name, escapePattern);
197         }
198 
199         if (prefix == null || prefix.equals("") || name.indexOf(".") >= 0)
200         {
201             return name;
202         }
203 
204         return prefix + "." + name;
205     }
206 	
207     
208     /**
209      * @param name
210      * @param escapePattern
211      * @return
212      */
213     private String getEscapedName(String name, String escapePattern)
214     {
215         logger.debug("getEscapedName(name={}, escapePattern={}) - start", name, escapePattern);
216 
217         if (name == null)
218         {
219             return name;
220         }
221 
222         if (escapePattern == null) 
223         {
224             throw new NullPointerException(
225                     "The parameter 'escapePattern' must not be null");
226         }
227         if(escapePattern.trim().equals(""))
228         {
229             throw new DatabaseUnitRuntimeException("Empty string is an invalid escape pattern!");
230         }
231     
232         int split = name.indexOf(".");
233         if (split > 1)
234         {
235         	return getEscapedName(name.substring(0, split), escapePattern) + "." + getEscapedName(name.substring(split + 1), escapePattern);
236         }
237 
238         int index = escapePattern.indexOf("?");
239         if (index >=0 )
240         {
241             String prefix = escapePattern.substring(0, index);
242             String suffix = escapePattern.substring(index + 1);
243 
244             return prefix + name + suffix;
245         }
246         else if(escapePattern.length() == 1)
247         {
248             // No "?" in the escape pattern and only one character.
249             // use the given escapePattern to surround the given name
250             return escapePattern + name + escapePattern;
251         }
252         else
253         {
254             logger.warn("Invalid escape pattern '" + escapePattern + "'. Will not escape name '" + name + "'.");
255             return name;
256         }
257     }
258 
259 }