Java tutorial
/* * Copyright 2009-2011 Collaborative Research Centre SFB 632 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package annis.sqlgen; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import org.apache.commons.lang3.StringUtils; import annis.model.QueryNode; import annis.ql.parser.QueryData; import org.springframework.util.Assert; /** * Abstract base class for a complete SQL statement. * * A SQL statement consists of a mandatory SELECT and FROM clauses and optional * WHERE, GROUP BY, ORDER BY and LIMIT/OFFSET clauses. The individual clauses * are generated using helper classes which are specified by properties. * * @author Viktor Rosenfeld <rosenfel@informatik.hu-berlin.de> * * @param <T> Type into which the JDBC result set is transformed. */ public abstract class AbstractSqlGenerator<T> extends TableAccessStrategyFactory implements SqlGenerator<QueryData, T> { // generators for different SQL statement clauses private WithClauseSqlGenerator<QueryData> withClauseSqlGenerator; private SelectClauseSqlGenerator<QueryData> selectClauseSqlGenerator; private List<FromClauseSqlGenerator<QueryData>> fromClauseSqlGenerators; private List<WhereClauseSqlGenerator<QueryData>> whereClauseSqlGenerators; private GroupByClauseSqlGenerator<QueryData> groupByClauseSqlGenerator; private OrderByClauseSqlGenerator<QueryData> orderByClauseSqlGenerator; private LimitOffsetClauseSqlGenerator<QueryData> limitOffsetClauseSqlGenerator; // controls indentation public final static String TABSTOP = " "; @Override public String toSql(QueryData queryData) { return toSql(queryData, ""); } @Override public String toSql(QueryData queryData, String indent) { Assert.notEmpty(queryData.getAlternatives(), "BUG: no alternatives"); // push alternative down List<QueryNode> alternative = queryData.getAlternatives().get(0); StringBuffer sb = new StringBuffer(); sb.append(indent); sb.append(createSqlForAlternative(queryData, alternative, indent)); appendOrderByClause(sb, queryData, alternative, indent); appendLimitOffsetClause(sb, queryData, alternative, indent); return sb.toString(); } protected String createSqlForAlternative(QueryData queryData, List<QueryNode> alternative, String indent) { StringBuffer sb = new StringBuffer(); appendWithClause(sb, queryData, alternative, indent); appendSelectClause(sb, queryData, alternative, indent); appendFromClause(sb, queryData, alternative, indent); appendWhereClause(sb, queryData, alternative, indent); appendGroupByClause(sb, queryData, alternative, indent); return sb.toString(); } protected String computeIndent(int indentBy) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < indentBy; ++i) { sb.append(TABSTOP); } return sb.toString(); } private void appendWithClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { if (withClauseSqlGenerator != null) { List<String> clauses = withClauseSqlGenerator.withClauses(queryData, alternative, indent + TABSTOP); if (!clauses.isEmpty()) { sb.append(indent).append("WITH\n"); sb.append(StringUtils.join(clauses, ",\n")); sb.append("\n"); } } } private void appendSelectClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { sb.append("SELECT "); sb.append(selectClauseSqlGenerator.selectClause(queryData, alternative, indent)); sb.append("\n"); } private void appendFromClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { sb.append(indent); sb.append("FROM"); List<String> fromTables = new ArrayList<String>(); for (FromClauseSqlGenerator<QueryData> generator : fromClauseSqlGenerators) { fromTables.add(generator.fromClause(queryData, alternative, indent)); } sb.append("\n"); sb.append(indent).append(TABSTOP); sb.append(StringUtils.join(fromTables, ",\n" + indent + TABSTOP)); sb.append("\n"); } private void appendWhereClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { // check if the WHERE clause generators are really used if (whereClauseSqlGenerators == null || whereClauseSqlGenerators.isEmpty()) { return; } // treat each condition as mutable string to remove last AND List<StringBuffer> conditions = new ArrayList<StringBuffer>(); for (WhereClauseSqlGenerator<QueryData> generator : whereClauseSqlGenerators) { Set<String> whereConditions = generator.whereConditions(queryData, alternative, indent); for (String constraint : whereConditions) { conditions.add(new StringBuffer(constraint)); } } // sort conditions, group by accessed table alias Collections.sort(conditions, new Comparator<StringBuffer>() { @Override public int compare(StringBuffer o1, StringBuffer o2) { if (o1 == null && o2 == null) { return 0; } else if (o1 == null && o2 != null) { return -1; } else if (o1 != null && o2 == null) { return 1; } else if (o1 != null && o2 != null) { return o1.toString().compareTo(o2.toString()); } throw new IllegalArgumentException("Could not compare " + o1 + " with " + o2); } }); // no conditions in WHERE clause? break out if (conditions.isEmpty()) { return; } // append WHERE clause to query sb.append(indent); sb.append("WHERE"); sb.append("\n"); sb.append(indent).append(TABSTOP); sb.append(StringUtils.join(conditions, " AND\n" + indent + TABSTOP)); sb.append("\n"); } private void appendGroupByClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { if (groupByClauseSqlGenerator != null) { sb.append(indent); sb.append("GROUP BY "); sb.append(groupByClauseSqlGenerator.groupByAttributes(queryData, alternative)); sb.append("\n"); } } protected void appendOrderByClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { if (orderByClauseSqlGenerator != null) { sb.append(indent); sb.append("ORDER BY "); sb.append(orderByClauseSqlGenerator.orderByClause(queryData, alternative, indent)); sb.append("\n"); } } protected void appendLimitOffsetClause(StringBuffer sb, QueryData queryData, List<QueryNode> alternative, String indent) { if (limitOffsetClauseSqlGenerator != null) { sb.append(indent); sb.append(limitOffsetClauseSqlGenerator.limitOffsetClause(queryData, alternative, indent)); sb.append("\n"); } } ///// Getter / Setter public List<FromClauseSqlGenerator<QueryData>> getFromClauseSqlGenerators() { return fromClauseSqlGenerators; } public void setFromClauseSqlGenerators(List<FromClauseSqlGenerator<QueryData>> fromClauseSqlGenerators) { this.fromClauseSqlGenerators = fromClauseSqlGenerators; } public List<WhereClauseSqlGenerator<QueryData>> getWhereClauseSqlGenerators() { return whereClauseSqlGenerators; } public void setWhereClauseSqlGenerators(List<WhereClauseSqlGenerator<QueryData>> whereClauseSqlGenerators) { this.whereClauseSqlGenerators = whereClauseSqlGenerators; } public GroupByClauseSqlGenerator<QueryData> getGroupByClauseSqlGenerator() { return groupByClauseSqlGenerator; } public void setGroupByClauseSqlGenerator(GroupByClauseSqlGenerator<QueryData> groupByClauseSqlGenerator) { this.groupByClauseSqlGenerator = groupByClauseSqlGenerator; } public WithClauseSqlGenerator<QueryData> getWithClauseSqlGenerator() { return withClauseSqlGenerator; } public void setWithClauseSqlGenerator(WithClauseSqlGenerator<QueryData> withClauseSqlGenerator) { this.withClauseSqlGenerator = withClauseSqlGenerator; } public SelectClauseSqlGenerator<QueryData> getSelectClauseSqlGenerator() { return selectClauseSqlGenerator; } public void setSelectClauseSqlGenerator(SelectClauseSqlGenerator<QueryData> selectClauseSqlGenerator) { this.selectClauseSqlGenerator = selectClauseSqlGenerator; } public OrderByClauseSqlGenerator<QueryData> getOrderByClauseSqlGenerator() { return orderByClauseSqlGenerator; } public void setOrderByClauseSqlGenerator(OrderByClauseSqlGenerator<QueryData> orderByClauseSqlGenerator) { this.orderByClauseSqlGenerator = orderByClauseSqlGenerator; } public LimitOffsetClauseSqlGenerator<QueryData> getLimitOffsetClauseSqlGenerator() { return limitOffsetClauseSqlGenerator; } public void setLimitOffsetClauseSqlGenerator( LimitOffsetClauseSqlGenerator<QueryData> limitOffsetClauseSqlGenerator) { this.limitOffsetClauseSqlGenerator = limitOffsetClauseSqlGenerator; } }