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.jdbc.metadata;
023:
024: import java.lang.reflect.Method;
025:
026: import org.w3c.dom.Element;
027:
028: import org.jboss.deployment.DeploymentException;
029: import org.jboss.metadata.MetaData;
030:
031: /**
032: * Imutable class contains information about a declated query.
033: *
034: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
035: * @version $Revision: 57209 $
036: */
037: public final class JDBCDeclaredQueryMetaData implements
038: JDBCQueryMetaData {
039: /**
040: * The method to which this query is bound.
041: */
042: private final Method method;
043:
044: /**
045: * The user specified additional columns to be added to the select clause.
046: */
047: private final String additionalColumns;
048:
049: /**
050: * The user specified from clause.
051: */
052: private final String from;
053:
054: /**
055: * The user specified where clause.
056: */
057: private final String where;
058:
059: /**
060: * The user specified order clause.
061: */
062: private final String order;
063:
064: /**
065: * The other clause is appended to the end of the sql. This is useful for
066: * hints to the query engine.
067: */
068: private final String other;
069:
070: /**
071: * Should the select be DISTINCT?
072: */
073: private final boolean distinct;
074:
075: /**
076: * The name of the ejb from which the field will be selected.
077: */
078: private final String ejbName;
079:
080: /**
081: * The name of the cmp-field to be selected.
082: */
083: private final String fieldName;
084:
085: /**
086: * The aliase that is used for the main select table.
087: */
088: private final String alias;
089: /**
090: * Read ahead meta data.
091: */
092: private final JDBCReadAheadMetaData readAhead;
093:
094: /**
095: * Should the query return Local or Remote beans.
096: */
097: private final boolean resultTypeMappingLocal;
098:
099: private final Class compiler;
100:
101: private final boolean lazyResultSetLoading;
102:
103: /**
104: * Constructs a JDBCDeclaredQueryMetaData which is defined by the
105: * declared-sql xml element and is invoked by the specified method.
106: * Inherits unspecified values from the defaults.
107: *
108: * @param defaults the default values to use
109: * @param readAhead the read-ahead properties for this query
110: */
111: public JDBCDeclaredQueryMetaData(
112: JDBCDeclaredQueryMetaData defaults,
113: JDBCReadAheadMetaData readAhead, Class compiler,
114: boolean lazyResultSetLoading) throws DeploymentException {
115: this .method = defaults.getMethod();
116: this .readAhead = readAhead;
117:
118: this .from = defaults.getFrom();
119: this .where = defaults.getWhere();
120: this .order = defaults.getOrder();
121: this .other = defaults.getOther();
122:
123: this .resultTypeMappingLocal = defaults
124: .isResultTypeMappingLocal();
125:
126: this .distinct = defaults.isSelectDistinct();
127: this .ejbName = defaults.getEJBName();
128: this .fieldName = defaults.getFieldName();
129: this .alias = defaults.getAlias();
130: this .additionalColumns = defaults.getAdditionalColumns();
131:
132: this .compiler = compiler;
133: this .lazyResultSetLoading = lazyResultSetLoading;
134: }
135:
136: /**
137: * Constructs a JDBCDeclaredQueryMetaData which is defined by the
138: * declared-sql xml element and is invoked by the specified method.
139: *
140: * @param queryElement the xml Element which contains the metadata about
141: * this query
142: * @param method the method which invokes this query
143: * @param readAhead the read-ahead properties for this query
144: */
145: public JDBCDeclaredQueryMetaData(boolean isResultTypeMappingLocal,
146: Element queryElement, Method method,
147: JDBCReadAheadMetaData readAhead, Class compiler,
148: boolean lazyResultSetLoading) throws DeploymentException {
149: this .compiler = compiler;
150: this .lazyResultSetLoading = lazyResultSetLoading;
151:
152: this .method = method;
153: this .readAhead = readAhead;
154:
155: from = nullIfEmpty(MetaData.getOptionalChildContent(
156: queryElement, "from"));
157: where = nullIfEmpty(MetaData.getOptionalChildContent(
158: queryElement, "where"));
159: order = nullIfEmpty(MetaData.getOptionalChildContent(
160: queryElement, "order"));
161: other = nullIfEmpty(MetaData.getOptionalChildContent(
162: queryElement, "other"));
163:
164: this .resultTypeMappingLocal = isResultTypeMappingLocal;
165:
166: // load ejbSelect info
167: Element selectElement = MetaData.getOptionalChild(queryElement,
168: "select");
169:
170: if (selectElement != null) {
171: // should select use distinct?
172: distinct = (MetaData.getOptionalChild(selectElement,
173: "distinct") != null);
174:
175: if (method.getName().startsWith("ejbSelect")) {
176: ejbName = MetaData.getUniqueChildContent(selectElement,
177: "ejb-name");
178: fieldName = nullIfEmpty(MetaData
179: .getOptionalChildContent(selectElement,
180: "field-name"));
181: } else {
182: // the ejb-name and field-name elements are not allowed for finders
183: if (MetaData
184: .getOptionalChild(selectElement, "ejb-name") != null) {
185: throw new DeploymentException(
186: "The ejb-name element of declared-sql select is only "
187: + "allowed for ejbSelect queries.");
188: }
189: if (MetaData.getOptionalChild(selectElement,
190: "field-name") != null) {
191: throw new DeploymentException(
192: "The field-name element of declared-sql select is only "
193: + "allowed for ejbSelect queries.");
194: }
195: ejbName = null;
196: fieldName = null;
197: }
198: alias = nullIfEmpty(MetaData.getOptionalChildContent(
199: selectElement, "alias"));
200: additionalColumns = nullIfEmpty(MetaData
201: .getOptionalChildContent(selectElement,
202: "additional-columns"));
203: } else {
204: if (method.getName().startsWith("ejbSelect")) {
205: throw new DeploymentException(
206: "The select element of "
207: + "declared-sql is required for ejbSelect queries.");
208: }
209: distinct = false;
210: ejbName = null;
211: fieldName = null;
212: alias = null;
213: additionalColumns = null;
214: }
215: }
216:
217: // javadoc in parent class
218: public Method getMethod() {
219: return method;
220: }
221:
222: // javadoc in parent class
223: public boolean isResultTypeMappingLocal() {
224: return resultTypeMappingLocal;
225: }
226:
227: /**
228: * Gets the read ahead metadata for the query.
229: *
230: * @return the read ahead metadata for the query.
231: */
232: public JDBCReadAheadMetaData getReadAhead() {
233: return readAhead;
234: }
235:
236: public Class getQLCompilerClass() {
237: return compiler;
238: }
239:
240: /**
241: * Gets the sql FROM clause of this query.
242: *
243: * @return a String which contains the sql FROM clause
244: */
245: public String getFrom() {
246: return from;
247: }
248:
249: /**
250: * Gets the sql WHERE clause of this query.
251: *
252: * @return a String which contains the sql WHERE clause
253: */
254: public String getWhere() {
255: return where;
256: }
257:
258: /**
259: * Gets the sql ORDER BY clause of this query.
260: *
261: * @return a String which contains the sql ORDER BY clause
262: */
263: public String getOrder() {
264: return order;
265: }
266:
267: /**
268: * Gets other sql code which is appended to the end of the query.
269: * This is userful for supplying hints to the query engine.
270: *
271: * @return a String which contains additional sql code which is
272: * appended to the end of the query
273: */
274: public String getOther() {
275: return other;
276: }
277:
278: /**
279: * Should the select be DISTINCT?
280: *
281: * @return true if the select clause should contain distinct
282: */
283: public boolean isSelectDistinct() {
284: return distinct;
285: }
286:
287: /**
288: * The name of the ejb from which the field will be selected.
289: *
290: * @return the name of the ejb from which a field will be selected, or null
291: * if returning a whole ejb
292: */
293: public String getEJBName() {
294: return ejbName;
295: }
296:
297: /**
298: * The name of the cmp-field to be selected.
299: *
300: * @return the name of the cmp-field to be selected or null if returning a
301: * whole ejb
302: */
303: public String getFieldName() {
304: return fieldName;
305: }
306:
307: /**
308: * The alias that is used for the select table.
309: *
310: * @return the alias that is used for the table from which the entity or
311: * field is selected.
312: */
313: public String getAlias() {
314: return alias;
315: }
316:
317: /**
318: * Additional columns that should be added to the select clause. For example,
319: * columns that are used in an order by clause.
320: *
321: * @return additional columns that should be added to the select clause
322: */
323: public String getAdditionalColumns() {
324: return additionalColumns;
325: }
326:
327: public boolean isLazyResultSetLoading() {
328: return lazyResultSetLoading;
329: }
330:
331: /**
332: * Compares this JDBCDeclaredQueryMetaData against the specified object.
333: * Returns true if the objects are the same. Two JDBCDeclaredQueryMetaData
334: * are the same if they are both invoked by the same method.
335: *
336: * @param o the reference object with which to compare
337: * @return true if this object is the same as the object argument; false
338: * otherwise
339: */
340: public boolean equals(Object o) {
341: if (o instanceof JDBCDeclaredQueryMetaData) {
342: return ((JDBCDeclaredQueryMetaData) o).method
343: .equals(method);
344: }
345: return false;
346: }
347:
348: /**
349: * Returns a hashcode for this JDBCDeclaredQueryMetaData. The hashcode is
350: * computed by the method which invokes this query.
351: *
352: * @return a hash code value for this object
353: */
354: public int hashCode() {
355: return method.hashCode();
356: }
357:
358: /**
359: * Returns a string describing this JDBCDeclaredQueryMetaData. The exact
360: * details of the representation are unspecified and subject to change,
361: * but the following may be regarded as typical:
362: * <p/>
363: * "[JDBCDeclaredQueryMetaData: method=public org.foo.User findByName(
364: * java.lang.String)]"
365: *
366: * @return a string representation of the object
367: */
368: public String toString() {
369: return "[JDBCDeclaredQueryMetaData : method=" + method + "]";
370: }
371:
372: private static String nullIfEmpty(String s) {
373: if (s != null && s.trim().length() == 0) {
374: s = null;
375: }
376: return s;
377: }
378: }
|