001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc2;
023:
024: import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCEntityBridge2;
025: import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCCMPFieldBridge2;
026: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCDeclaredQueryMetaData;
027: import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil;
028: import org.jboss.ejb.plugins.cmp.jdbc.QueryParameter;
029: import org.jboss.ejb.plugins.cmp.ejbql.Catalog;
030: import org.jboss.deployment.DeploymentException;
031: import org.jboss.logging.Logger;
032:
033: import java.util.ArrayList;
034: import java.util.StringTokenizer;
035:
036: /**
037: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
038: * @version <tt>$Revision: 61754 $</tt>
039: */
040: public class DeclaredSQLQueryCommand extends AbstractQueryCommand {
041: private JDBCCMPFieldBridge2 selectedField;
042:
043: public DeclaredSQLQueryCommand(JDBCEntityBridge2 entity,
044: JDBCDeclaredQueryMetaData metadata)
045: throws DeploymentException {
046: initResultReader(entity, metadata);
047:
048: this .sql = buildSQL(metadata);
049: this .sql = parseParameters(this .sql, metadata);
050:
051: setResultType(metadata.getMethod().getReturnType());
052:
053: log = Logger.getLogger(getClass().getName() + "."
054: + entity.getEntityName() + "#"
055: + metadata.getMethod().getName());
056: log.debug("sql: " + sql);
057: }
058:
059: private void initResultReader(JDBCEntityBridge2 entity,
060: JDBCDeclaredQueryMetaData metadata)
061: throws DeploymentException {
062: String entityName = metadata.getEJBName();
063:
064: if (entityName != null) {
065: Catalog catalog = entity.getManager().getCatalog();
066: JDBCEntityBridge2 otherEntity = (JDBCEntityBridge2) catalog
067: .getEntityByEJBName(entityName);
068: if (otherEntity == null) {
069: throw new DeploymentException("Unknown entity: "
070: + entityName);
071: }
072: this .entity = otherEntity;
073: } else {
074: this .entity = entity;
075: }
076:
077: String fieldName = metadata.getFieldName();
078: if (fieldName == null) {
079: setEntityReader(this .entity, metadata.isSelectDistinct());
080: } else {
081: selectedField = (JDBCCMPFieldBridge2) entity
082: .getFieldByName(fieldName);
083: if (selectedField == null) {
084: throw new DeploymentException("Unknown cmp field: "
085: + fieldName);
086: }
087:
088: setFieldReader(selectedField);
089: }
090: }
091:
092: private String buildSQL(JDBCDeclaredQueryMetaData metadata) {
093: StringBuffer sql = new StringBuffer(300);
094:
095: sql.append(SQLUtil.SELECT);
096: if (metadata.isSelectDistinct()) {
097: sql.append(SQLUtil.DISTINCT);
098: }
099:
100: String alias = metadata.getAlias();
101: String from = metadata.getFrom();
102: String table;
103: String selectList;
104: if (metadata.getFieldName() == null) {
105: // we are selecting a full entity
106: table = this .entity.getQualifiedTableName();
107:
108: // get a list of all fields to be loaded
109: // put pk fields in front
110: String tableAlias = getTableAlias(alias, from, this .entity
111: .getTableName());
112: selectList = SQLUtil.getColumnNamesClause(
113: this .entity.getPrimaryKeyFields(), tableAlias,
114: new StringBuffer(35)).toString();
115: } else {
116: // we are just selecting one field
117: JDBCStoreManager2 manager = (JDBCStoreManager2) selectedField
118: .getManager();
119: table = manager.getEntityBridge().getQualifiedTableName();
120: selectList = SQLUtil.getColumnNamesClause(
121: selectedField,
122: getTableAlias(alias, from, manager
123: .getEntityBridge().getTableName()),
124: new StringBuffer()).toString();
125: }
126: sql.append(selectList);
127: String additionalColumns = metadata.getAdditionalColumns();
128: if (additionalColumns != null) {
129: sql.append(additionalColumns);
130: }
131: sql.append(SQLUtil.FROM).append(table);
132: if (alias != null) {
133: sql.append(' ').append(alias);
134: }
135: if (from != null) {
136: sql.append(' ').append(from);
137: }
138:
139: String where = metadata.getWhere();
140: if (where != null && where.trim().length() > 0) {
141: sql.append(SQLUtil.WHERE).append(where);
142: }
143:
144: String order = metadata.getOrder();
145: if (order != null && order.trim().length() > 0) {
146: sql.append(SQLUtil.ORDERBY).append(order);
147: }
148:
149: String other = metadata.getOther();
150: if (other != null && other.trim().length() > 0) {
151: sql.append(' ').append(other);
152: }
153: return sql.toString();
154: }
155:
156: private static String getTableAlias(String alias, String from,
157: String table) {
158: String tableAlias;
159: if (alias != null) {
160: tableAlias = alias;
161: } else if (from != null) {
162: tableAlias = table;
163: } else {
164: tableAlias = SQLUtil.EMPTY_STRING;
165: }
166: return tableAlias;
167: }
168:
169: /**
170: * Replaces the parameters in the specific sql with question marks, and
171: * initializes the parameter setting code. Parameters are encoded in curly
172: * brackets use a zero based index.
173: *
174: * @param sql the sql statement that is parsed for parameters
175: * @return the original sql statement with the parameters replaced with a
176: * question mark
177: * @throws DeploymentException if a error occures while parsing the sql
178: */
179: protected String parseParameters(String sql,
180: JDBCDeclaredQueryMetaData metadata)
181: throws DeploymentException {
182: StringBuffer sqlBuf = new StringBuffer();
183: ArrayList params = new ArrayList();
184:
185: // Replace placeholders {0} with ?
186: if (sql != null) {
187: sql = sql.trim();
188:
189: StringTokenizer tokens = new StringTokenizer(sql, "{}",
190: true);
191: while (tokens.hasMoreTokens()) {
192: String token = tokens.nextToken();
193: if (token.equals("{")) {
194: token = tokens.nextToken();
195: if (Character.isDigit(token.charAt(0))) {
196: QueryParameter parameter = new QueryParameter(
197: entity.getManager(), metadata
198: .getMethod(), token);
199:
200: // of if we are here we can assume that we have
201: // a parameter and not a function
202: sqlBuf.append("?");
203: params.add(parameter);
204:
205: if (!tokens.nextToken().equals("}")) {
206: throw new DeploymentException(
207: "Invalid parameter - missing closing '}' : "
208: + sql);
209: }
210: } else {
211: // ok we don't have a parameter, we have a function
212: // push the tokens on the buffer and continue
213: sqlBuf.append("{").append(token);
214: }
215: } else {
216: // not parameter... just append it
217: sqlBuf.append(token);
218: }
219: }
220: }
221:
222: setParameters(params);
223:
224: return sqlBuf.toString();
225: }
226: }
|