001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.ejb.ql;
030:
031: import com.caucho.amber.field.IdField;
032: import com.caucho.amber.field.KeyManyToOneField;
033: import com.caucho.amber.type.EntityType;
034: import com.caucho.config.ConfigException;
035: import com.caucho.ejb.cfg21.EjbEntityBean;
036: import com.caucho.util.CharBuffer;
037: import com.caucho.util.L10N;
038: import com.caucho.util.Log;
039:
040: import java.util.ArrayList;
041: import java.util.Collection;
042: import java.util.Collections;
043: import java.util.logging.Logger;
044:
045: /**
046: * Parsed expression for EJB-QL.
047: */
048: public class Expr {
049: static final Logger log = Log.open(Expr.class);
050: static final L10N L = new L10N(Expr.class);
051:
052: protected Query _query;
053:
054: // The type of the expression value
055: private Class _javaType;
056:
057: /**
058: * Gets the Java Type of the expression.
059: */
060: public Class getJavaType() {
061: return _javaType;
062: }
063:
064: /**
065: * Sets the Java Type of the expression.
066: */
067: void setJavaType(Class javaType) {
068: _javaType = javaType;
069: }
070:
071: /**
072: * Returns the EJB name.
073: */
074: String getReturnEJB() {
075: return null;
076: }
077:
078: /**
079: * Returns true for object values.
080: */
081: boolean isKey() {
082: return getReturnEJB() != null;
083: }
084:
085: /**
086: * True if the type is numeric.
087: */
088: boolean isNumeric() {
089: Class type = getJavaType();
090:
091: if (type == null)
092: return false;
093:
094: String typeName = type.getName();
095:
096: if ("java.lang.Byte".equals(typeName)
097: || "java.lang.Short".equals(typeName)
098: || "java.lang.Integer".equals(typeName)
099: || "java.lang.Long".equals(typeName)
100: || "java.lang.Float".equals(typeName)
101: || "java.lang.Double".equals(typeName))
102: return true;
103: else if (!type.isPrimitive())
104: return false;
105: else if (typeName.equals("boolean") || typeName.equals("char"))
106: return false;
107: else
108: return true;
109: }
110:
111: /**
112: * True if the type is integer.
113: */
114: boolean isInteger() {
115: Class type = getJavaType();
116: String typeName = type.getName();
117:
118: return ("java.lang.Byte".equals(typeName)
119: || "java.lang.Short".equals(typeName)
120: || "java.lang.Integer".equals(typeName)
121: || "java.lang.Long".equals(typeName)
122: || "byte".equals(typeName) || "short".equals(typeName)
123: || "int".equals(typeName) || "long".equals(typeName));
124: }
125:
126: /**
127: * True if the type is integer.
128: */
129: static boolean isInteger(Class type) {
130: String typeName = type.getName();
131:
132: return ("java.lang.Byte".equals(typeName)
133: || "java.lang.Short".equals(typeName)
134: || "java.lang.Integer".equals(typeName)
135: || "java.lang.Long".equals(typeName)
136: || "byte".equals(typeName) || "short".equals(typeName)
137: || "int".equals(typeName) || "long".equals(typeName));
138: }
139:
140: int getComponentCount() {
141: return 1;
142: }
143:
144: /**
145: * True if the type is a string.
146: */
147: boolean isString() {
148: Class type = getJavaType();
149: String typeName = type.getName();
150:
151: return ("java.lang.String".equals(typeName)
152: || "char".equals(typeName) || "java.lang.Character"
153: .equals(typeName));
154: }
155:
156: /**
157: * True if the type is a boolean.
158: */
159: boolean isBoolean() {
160: Class type = getJavaType();
161: String typeName = type.getName();
162:
163: return ("boolean".equals(typeName) || "java.lang.Boolean"
164: .equals(typeName));
165: }
166:
167: /**
168: * True if the type is a date.
169: */
170: boolean isDate() {
171: Class type = getJavaType();
172: String typeName = type.getName();
173:
174: return ("java.util.Date".equals(typeName)
175: || "java.sql.Timestamp".equals(typeName)
176: || "java.sql.Date".equals(typeName) || "java.sql.Time"
177: .equals(typeName));
178: }
179:
180: /**
181: * Only args can be coerced.
182: */
183: boolean canCoerce() {
184: return false;
185: }
186:
187: /**
188: * True if the type is a collection.
189: */
190: boolean isCollection() {
191: Class type = getJavaType();
192:
193: return Collection.class.isAssignableFrom(type);
194: }
195:
196: /**
197: * True if the bean refers to an external entity bean.
198: */
199: boolean isExternal() {
200: return false;
201: }
202:
203: /**
204: * Returns the item bean of a collection.
205: */
206: EjbEntityBean getItemBean() {
207: return null;
208: }
209:
210: /**
211: * Creates a field expression from this expression.
212: */
213: Expr newField(String field) throws ConfigException {
214: throw error(L
215: .l(
216: "'{0}' can't have field '{1}'. Only path expressions referring to a single bean have fields.",
217: this , field));
218: }
219:
220: /**
221: * Creates an external entity reference from this expression.
222: */
223: FieldExpr newReference(String field) throws ConfigException {
224: throw error(L
225: .l("'{0}' can't have reference '{1}'", this , field));
226: }
227:
228: /**
229: * Evaluates the types for the expression
230: */
231: void evalTypes() throws ConfigException {
232: if (getJavaType() == null)
233: throw error(L.l("'{0}' has no type.", this ) + getClass());
234: }
235:
236: /**
237: * Prints the select SQL for this expression
238: */
239: void generateSelect(CharBuffer cb) {
240: generateWhere(cb);
241: }
242:
243: /**
244: * Returns the select's table
245: */
246: String getSelectTable(CharBuffer cb) throws ConfigException {
247: throw new IllegalStateException(L.l(
248: "'{0}' can't be used in a SELECT expression", this ));
249: }
250:
251: /**
252: * Prints the where SQL for this expression
253: */
254: void generateWhere(CharBuffer cb) {
255: throw new IllegalStateException(L.l(
256: "{0}: '{1}' can't be used in a WHERE expression",
257: getClass().getName(), this ));
258: }
259:
260: /**
261: * Prints the where SQL for this expression
262: */
263: void generateWhereSubExpr(CharBuffer cb) {
264: generateWhere(cb);
265: }
266:
267: /**
268: * Prints the where SQL for this expression
269: */
270: void generateComponent(CharBuffer cb, int i) {
271: if (i == 0)
272: generateWhereSubExpr(cb);
273: else
274: throw new IllegalStateException(L.l(
275: "'{0}' can't be used in a WHERE multi-component",
276: this ));
277: }
278:
279: protected String keyComponent(EntityType type, int index) {
280: ArrayList<String> names = new ArrayList<String>();
281:
282: addKeys(names, type, "");
283:
284: Collections.sort(names);
285:
286: return names.get(index);
287: }
288:
289: protected void addKeys(ArrayList<String> names, EntityType type,
290: String prefix) {
291: for (IdField key : type.getId().getKeys()) {
292: if (key instanceof KeyManyToOneField) {
293: KeyManyToOneField manyToOne = (KeyManyToOneField) key;
294:
295: addKeys(names, manyToOne.getEntityType(), prefix
296: + key.getName() + ".");
297: } else
298: names.add(prefix + key.getName());
299: }
300: }
301:
302: /**
303: * Creates an error.
304: */
305: ConfigException error(String msg) {
306: if (_query != null)
307: return _query.error(msg);
308: else
309: return new ConfigException(msg);
310: }
311:
312: /**
313: * Creates an error.
314: */
315: ConfigException error(Query query, String msg) {
316: return query.error(msg);
317: }
318: }
|