001: /**********************************************************************
002: Copyright (c) 2002 Kelly Grizzle (TJDO) and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015:
016: Contributors:
017: 2002 Mike Martin (TJDO)
018: 2003 Andy Jefferson - coding standards
019: 2005 Andy Jefferson - added support for result set type/concurrency
020: 2007 Andy Jefferson - removed RDBMS dependency
021: ...
022: **********************************************************************/package org.jpox.store.query;
023:
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import org.jpox.ObjectManager;
031: import org.jpox.store.expression.QueryExpression;
032: import org.jpox.store.expression.ScalarExpression;
033: import org.jpox.store.mapping.JavaTypeMapping;
034: import org.jpox.store.mapping.Mappings;
035:
036: /**
037: * Representation of a statement.
038: *
039: * @version $Revision: 1.1 $
040: **/
041: public class StatementText {
042: private static int nextParamID = 0;
043:
044: private StringBuffer statementText;
045: private List parameterNames = null;
046: private Map parameterMappingsByName = null;
047: private Map parameterValuesByName = null;
048: private boolean encloseWithInParentheses = false;
049: private String postpend;
050: private List appended;
051:
052: /**
053: * Constructor
054: **/
055: public StatementText() {
056: appended = new ArrayList();
057: }
058:
059: /**
060: * Constructor
061: * @param initialStatementText
062: */
063: public StatementText(String initialStatementText) {
064: this ();
065: append(initialStatementText);
066: }
067:
068: /**
069: * Convenience method to reset the SQL for the statement.
070: * This is used when updating an expression internally, and need to regenerate
071: * the statement.
072: */
073: public void clearStatement() {
074: statementText = null;
075: appended.clear();
076: }
077:
078: /**
079: * Method to initialise the statement.
080: */
081: private void initParameters() {
082: if (parameterNames == null) {
083: parameterNames = new ArrayList();
084: parameterMappingsByName = new HashMap();
085: parameterValuesByName = new HashMap();
086: }
087: }
088:
089: /**
090: * Whether to enclose this statement within parentheses
091: */
092: public void encloseWithInParentheses() {
093: statementText = null;
094: this .encloseWithInParentheses = true;
095: }
096:
097: /**
098: * Set a String to the end of the statement.
099: * @param s the string
100: * @return the StatementText
101: */
102: public StatementText postpend(String s) {
103: statementText = null;
104: postpend = s;
105: return this ;
106: }
107:
108: /**
109: * Append a char
110: * @param c the char
111: * @return the StatementText
112: */
113: public StatementText append(char c) {
114: statementText = null;
115: appended.add(new Character(c));
116: return this ;
117: }
118:
119: /**
120: * Append a char
121: * @param s the String
122: * @return the StatementText
123: */
124: public StatementText append(String s) {
125: statementText = null;
126: appended.add(s);
127: return this ;
128: }
129:
130: /**
131: * Append a QueryExpression
132: * @param qsc the QueryExpression
133: * @return the StatementText
134: */
135: public StatementText append(QueryExpression qsc) {
136: statementText = null;
137: appended.add(qsc);
138: return this ;
139: }
140:
141: /**
142: * Append a StatementText
143: * @param st the StatementText
144: * @return the StatementText
145: */
146: public StatementText append(StatementText st, int mode) {
147: appended.add(st.toStatementString(mode));
148: if (st.parameterNames != null) {
149: initParameters();
150: parameterNames.addAll(st.parameterNames);
151: parameterMappingsByName.putAll(st.parameterMappingsByName);
152: parameterValuesByName.putAll(st.parameterValuesByName);
153: }
154: return this ;
155: }
156:
157: /**
158: * Append a ScalarExpression
159: * @param expr the ScalarExpression
160: * @return the StatementText
161: */
162: public StatementText append(ScalarExpression expr) {
163: appended.add(expr);
164: return this ;
165: }
166:
167: /**
168: * Append a parameter
169: * @param mapping the mapping
170: * @param value the parameter value
171: * @return the generated parameter name
172: */
173: public String appendParameter(JavaTypeMapping mapping, Object value) {
174: statementText = null;
175: String name = "param-" + nextParamID++;
176: appended.add(new Parameter(name, mapping, value));
177: return name;
178: }
179:
180: /**
181: * Method to set the parameters in the datastore statement.
182: * @param om ObjectManager
183: * @param datastoreStatement The datastore "statement"
184: */
185: public void setParameters(ObjectManager om,
186: Object datastoreStatement) {
187: if (parameterNames != null) {
188: Iterator i = parameterNames.iterator();
189: int stmtParamNum = 1;
190:
191: while (i.hasNext()) {
192: Object name = i.next();
193: JavaTypeMapping mapping = (JavaTypeMapping) parameterMappingsByName
194: .get(name);
195: Object value = parameterValuesByName.get(name);
196:
197: mapping.setObject(om, datastoreStatement, Mappings
198: .getParametersIndex(stmtParamNum, mapping),
199: value);
200: if (mapping.getNumberOfDatastoreFields() > 0) {
201: stmtParamNum += mapping
202: .getNumberOfDatastoreFields();
203: } else {
204: //if the JavaTypeMapping has no datastoreFields, at least one it may have
205: stmtParamNum += 1;
206: }
207: }
208: }
209: }
210:
211: /**
212: * Accessor for the SQL of the statement.
213: * @param mode (0=PROJECTION;1=FILTER)
214: * @return The SQL text
215: */
216: public String toStatementString(int mode) {
217: if (statementText == null) {
218: statementText = new StringBuffer();
219: if (encloseWithInParentheses) {
220: statementText.append("(");
221: }
222: for (int i = 0; i < appended.size(); i++) {
223: Object item = appended.get(i);
224: if (item instanceof ScalarExpression) {
225: ScalarExpression expr = (ScalarExpression) item;
226: StatementText st = expr.toStatementText(mode);
227: statementText.append(st.toStatementString(mode));
228:
229: if (st.parameterNames != null) {
230: initParameters();
231: parameterNames.addAll(st.parameterNames);
232: parameterMappingsByName
233: .putAll(st.parameterMappingsByName);
234: parameterValuesByName
235: .putAll(st.parameterValuesByName);
236: }
237: } else if (item instanceof Parameter) {
238: Parameter param = (Parameter) item;
239: statementText.append('?');
240:
241: initParameters();
242: parameterNames.add(param.name);
243: parameterMappingsByName.put(param.name,
244: param.mapping);
245: parameterValuesByName.put(param.name, param.value);
246: } else if (item instanceof QueryExpression) {
247: QueryExpression qe = (QueryExpression) item;
248: StatementText st = qe.toStatementText(false); // TODO use the same lock as the caller
249: statementText.append(st.toStatementString(mode));
250: if (st.parameterNames != null) {
251: initParameters();
252: parameterNames.addAll(st.parameterNames);
253: parameterMappingsByName
254: .putAll(st.parameterMappingsByName);
255: parameterValuesByName
256: .putAll(st.parameterValuesByName);
257: }
258: } else if (item instanceof StatementText) {
259: StatementText st = (StatementText) item;
260: statementText.append(st.toStatementString(mode));
261: if (st.parameterNames != null) {
262: initParameters();
263: parameterNames.addAll(st.parameterNames);
264: parameterMappingsByName
265: .putAll(st.parameterMappingsByName);
266: parameterValuesByName
267: .putAll(st.parameterValuesByName);
268: }
269: } else {
270: statementText.append(item);
271: }
272: }
273: if (encloseWithInParentheses) {
274: statementText.append(")");
275: }
276: statementText.append((postpend == null ? "" : postpend));
277: }
278: return statementText.toString();
279: }
280:
281: /**
282: * Accessor for the string form of the statement.
283: * @return String form of the statement
284: */
285: public String toString() {
286: //the mode should be indifferent, so we use projection
287: return toStatementString(ScalarExpression.PROJECTION);
288: }
289:
290: /**
291: * Internal class to keep parameters
292: */
293: private class Parameter {
294: final String name;
295: final JavaTypeMapping mapping;
296: final Object value;
297:
298: public Parameter(String name, JavaTypeMapping mapping,
299: Object value) {
300: super();
301: this.name = name;
302: this.mapping = mapping;
303: this.value = value;
304: }
305: }
306: }
|