View Javadoc

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 }