1 package org.apache.torque;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.Serializable;
23
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.commons.lang.builder.EqualsBuilder;
26 import org.apache.commons.lang.builder.HashCodeBuilder;
27
28 /**
29 * An implementation of the column interface.
30 * This class is immutable, i.e cannot be changed once constructed.
31 *
32 * @version $Id: ColumnImpl.java 1335473 2012-05-08 12:35:24Z tfischer $
33 */
34 public class ColumnImpl implements Column, Serializable
35 {
36 /** Serial version uid. **/
37 private static final long serialVersionUID = 1L;
38
39 /** Delimiters for SQL functions. */
40 private static final String[] FUNCTION_DELIMITERS
41 = {" ", ",", "(", ")", "<", ">"};
42
43 /** Constant for the dot. */
44 private static final String DOT = ".";
45
46 /** The column name, may be null but not empty. */
47 private String columnName;
48
49 /** The table name, may be null but not empty. */
50 private String tableName;
51
52 /** The schema name, may be null but not empty. */
53 private String schemaName;
54
55 /** The SQL expression for the column, not null. */
56 private String sqlExpression;
57
58 /**
59 * Constructor.
60 *
61 * @param tableName the table name, not null or blank.
62 * @param columnName the column name, not null or blank.
63 *
64 * @throws NullPointerException if columnName or tableName are null.
65 * @throws IllegalArgumentException if columnName or tableName are blank.
66 */
67 public ColumnImpl(String tableName, String columnName)
68 {
69 if (columnName == null)
70 {
71 throw new NullPointerException("columnName must not be null");
72 }
73 if (tableName == null)
74 {
75 throw new NullPointerException("tableName must not be null");
76 }
77 setColumnName(columnName);
78 setTableName(tableName);
79 this.sqlExpression = tableName + DOT + columnName;
80 }
81
82 /**
83 * Constructor.
84 *
85 * @param schemaName the schema name, may be null but not blank.
86 * @param tableName the table name, may be null but not blank.
87 * If it contains a dot, then only the portion after the dot
88 * will be taken as table name.
89 * If it contains a dot and schemaName is null, then the schema
90 * name will be set as the portion before the dot.
91 * @param columnName the column name, not null or blank.
92 *
93 * @throws NullPointerException if columnName or tableName are null.
94 * @throws IllegalArgumentException if columnName or tableName are blank.
95 */
96 public ColumnImpl(String schemaName, String tableName, String columnName)
97 {
98 if (columnName == null)
99 {
100 throw new NullPointerException("columnName must not be null");
101 }
102 setColumnName(columnName);
103 setTableName(tableName);
104 setSchemaName(schemaName);
105 if (this.tableName == null)
106 {
107 this.sqlExpression = this.columnName;
108 }
109 else
110 {
111 this.sqlExpression = this.tableName + DOT + this.columnName;
112 }
113 }
114
115 /**
116 * Constructor.
117 *
118 * @param schemaName the schema name, may be null but not blank.
119 * @param tableName the table name, may be null but not blank.
120 * If it contains a dot, then only the portion after the dot
121 * will be taken as table name.
122 * If it contains a dot and schemaName is null, then the schema
123 * name will be set as the portion before the dot.
124 * @param columnName the column name, may be null but not blank.
125 * @param sqlExpression the SQL expression for the column,
126 * not null or blank.
127 *
128 * @throws NullPointerException if tableName or sqlExpression are null.
129 * @throws IllegalArgumentException if tableName or sqlExpression are blank.
130 */
131 public ColumnImpl(
132 String schemaName,
133 String tableName,
134 String columnName,
135 String sqlExpression)
136 {
137 setColumnName(columnName);
138 setTableName(tableName);
139 setSchemaName(schemaName);
140 setSqlExpression(sqlExpression);
141 }
142
143
144 /**
145 * Constructor which tries to guess schema, table and column names from
146 * an SQL expression. If a schema name can be identified in the
147 * SQL expression, it is removed from the SQL expression in the column.
148 *
149 * @param sqlExpression the SQL expression, not null, not blank.
150 *
151 * @throws NullPointerException if sqlExpression is null.
152 * @throws IllegalArgumentException if table or column name cannot be
153 * guessed from sqlExpression.
154 */
155 public ColumnImpl(String sqlExpression)
156 {
157 setSqlExpression(sqlExpression);
158
159 // Find Table.Column
160 int dotIndex = sqlExpression.lastIndexOf(DOT);
161 if (dotIndex == -1)
162 {
163 if (StringUtils.contains(sqlExpression, "*"))
164 {
165 return;
166 }
167 if (StringUtils.indexOfAny(sqlExpression, FUNCTION_DELIMITERS)
168 != -1)
169 {
170 throw new IllegalArgumentException("sqlExpression "
171 + sqlExpression
172 + " is unparseable, it does not contain a dot (.) "
173 + " but function delimiters.");
174 }
175 setColumnName(sqlExpression);
176 return;
177 }
178 String pre = sqlExpression.substring(0, dotIndex);
179 String post = sqlExpression.substring(
180 dotIndex + 1,
181 sqlExpression.length());
182 if (StringUtils.isBlank(pre))
183 {
184 throw new IllegalArgumentException("sqlExpression "
185 + sqlExpression
186 + " is blank before the dot (.)");
187 }
188 int startIndex = StringUtils.lastIndexOfAny(pre, FUNCTION_DELIMITERS);
189 int endIndex = StringUtils.indexOfAny(post, FUNCTION_DELIMITERS);
190 if (endIndex < 0)
191 {
192 endIndex = sqlExpression.length();
193 }
194 else
195 {
196 // relative to sqlExpression not to post
197 endIndex += dotIndex + 1;
198 }
199
200 if (startIndex + 1 == dotIndex)
201 {
202 throw new IllegalArgumentException("sqlExpression "
203 + sqlExpression
204 + " is blank between the last function delimiter ("
205 + StringUtils.join(FUNCTION_DELIMITERS)
206 + ") and the dot");
207 }
208 setColumnName(sqlExpression.substring(dotIndex + 1, endIndex));
209 // if startIndex == -1 the formula is correct
210 String fullTableName
211 = sqlExpression.substring(startIndex + 1, dotIndex);
212 setTableName(fullTableName);
213 if (fullTableName.contains(DOT))
214 {
215 int fullTableNameDotIndex = fullTableName.lastIndexOf(DOT);
216 String extractedSchemaName
217 = fullTableName.substring(0, fullTableNameDotIndex);
218 setSchemaName(extractedSchemaName);
219 StringBuilder sqlExpressionBuilder = new StringBuilder();
220 if (startIndex != -1)
221 {
222 sqlExpressionBuilder.append(
223 sqlExpression.substring(0, startIndex + 1));
224 }
225 sqlExpressionBuilder.append(getTableName())
226 .append(DOT)
227 .append(post);
228 setSqlExpression(sqlExpressionBuilder.toString());
229 }
230 }
231
232 /**
233 * Returns the column name.
234 *
235 * @return the column name, may be null.
236 */
237 public String getColumnName()
238 {
239 return columnName;
240 }
241
242 /**
243 * Sets the column name, using null if * is passed.
244 *
245 * @param columnName the column name, not blank.
246 */
247 private void setColumnName(String columnName)
248 {
249 if (columnName != null && StringUtils.isBlank(columnName))
250 {
251 throw new IllegalArgumentException("columnName must not be blank");
252 }
253 if ("*".equals(columnName))
254 {
255 this.columnName = null;
256 }
257 else
258 {
259 this.columnName = columnName;
260 }
261 }
262
263 /**
264 * Returns the table name.
265 *
266 * @return the table name, may be null.
267 */
268 public String getTableName()
269 {
270 return tableName;
271 }
272
273 /**
274 * {@inheritDoc}
275 */
276 public String getFullTableName()
277 {
278 if (schemaName != null)
279 {
280 return schemaName + '.' + tableName;
281 }
282 return tableName;
283 }
284
285 /**
286 * Sets the table name.
287 * If a table name with schema prefix is passed, then the unqualified table
288 * name is used as table name and the schema name will be set to the
289 * extracted schema name.
290 *
291 * @param tableName the table name, not blank, may be null.
292 *
293 * @throws IllegalArgumentException if tableName is blank or null.
294 */
295 private void setTableName(String tableName)
296 {
297 if (tableName != null && StringUtils.isBlank(tableName))
298 {
299 throw new IllegalArgumentException("tableName must not be blank");
300 }
301 if (StringUtils.contains(tableName, DOT))
302 {
303 int dotIndex = tableName.lastIndexOf(DOT);
304 this.schemaName = tableName.substring(0, dotIndex);
305 this.tableName = tableName.substring(dotIndex + 1);
306 return;
307 }
308 this.tableName = tableName;
309 }
310
311 /**
312 * Returns the name of any fixed schema prefix for the column's table
313 * (if any).
314 *
315 * @return the schema name, or null if the schema is not known.
316 */
317 public String getSchemaName()
318 {
319 return schemaName;
320 }
321
322 /**
323 * Sets the schema name, if a non-null value is passed.
324 *
325 * @param schemaName the schema name, or null.
326 *
327 * @throws IllegalArgumentException if schemaName is blank.
328 */
329 private void setSchemaName(String schemaName)
330 {
331 if (schemaName == null)
332 {
333 return;
334 }
335 if (StringUtils.isBlank(schemaName))
336 {
337 throw new IllegalArgumentException("schemaName must not be blank");
338 }
339 this.schemaName = schemaName;
340 }
341
342 /**
343 * {@inheritDoc}
344 */
345 public String getSqlExpression()
346 {
347 return sqlExpression;
348 }
349
350 /**
351 * Sets the sql expression.
352 *
353 * @param sqlExpression the sql expression, not null.
354 *
355 * @throws NullPointerException if sqlExpression is null.
356 * @throws IllegalArgumentException if sqlExpression is blank.
357 */
358 private void setSqlExpression(String sqlExpression)
359 {
360 if (sqlExpression == null)
361 {
362 throw new IllegalArgumentException(
363 "sqlExpression must not be null");
364 }
365 if (StringUtils.isBlank(sqlExpression))
366 {
367 throw new IllegalArgumentException(
368 "sqlExpression must not be blank");
369 }
370 this.sqlExpression = sqlExpression;
371 }
372
373 @Override
374 public int hashCode()
375 {
376 return new HashCodeBuilder()
377 .append(sqlExpression)
378 .append(columnName)
379 .append(tableName)
380 .append(schemaName)
381 .toHashCode();
382 }
383
384 @Override
385 public boolean equals(Object obj)
386 {
387 if (this == obj)
388 {
389 return true;
390 }
391 if (obj == null)
392 {
393 return false;
394 }
395 if (getClass() != obj.getClass())
396 {
397 return false;
398 }
399 ColumnImpl other = (ColumnImpl) obj;
400 return new EqualsBuilder()
401 .append(sqlExpression, other.sqlExpression)
402 .append(columnName, other.columnName)
403 .append(tableName, other.tableName)
404 .append(schemaName, other.schemaName)
405 .isEquals();
406 }
407
408 @Override
409 public String toString()
410 {
411 return "ColumnImpl [columnName=" + columnName
412 + ", tableName=" + tableName
413 + ", schemaName=" + schemaName
414 + ", sqlExpression=" + sqlExpression + "]";
415 }
416 }