001: /*
002: * Copyright 2004-2007 Gary Bentley
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may
005: * not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
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: package org.josql.expressions;
016:
017: import java.util.Map;
018: import java.util.TreeMap;
019: import java.util.LinkedHashMap;
020: import java.util.List;
021: import java.util.Iterator;
022:
023: import java.lang.reflect.Constructor;
024:
025: import org.josql.internal.Setter;
026: import org.josql.internal.Utilities;
027:
028: import org.josql.Query;
029: import org.josql.QueryParseException;
030: import org.josql.QueryExecutionException;
031:
032: public class NewObjectExpression extends ValueExpression {
033:
034: private String cn = null;
035: private Class clazz = null;
036: private List constructorArgs = null;
037: private Map intoExps = null;
038: private Constructor constructor = null;
039: private Object[] conParms = null;
040: private int argsSize = -1;
041:
042: public void addIntoExpression(Expression exp, String setter) {
043:
044: if (this .intoExps == null) {
045:
046: this .intoExps = new LinkedHashMap();
047:
048: }
049:
050: this .intoExps.put(exp, setter);
051:
052: }
053:
054: public void setConstructorArgs(List exps) {
055:
056: this .constructorArgs = exps;
057:
058: this .argsSize = exps.size() - 1;
059:
060: }
061:
062: public void setClassName(String c) {
063:
064: this .cn = c;
065:
066: }
067:
068: public boolean hasFixedResult(Query q) {
069:
070: return false;
071:
072: }
073:
074: public Class getExpectedReturnType(Query q)
075: throws QueryParseException {
076:
077: return this .clazz;
078:
079: }
080:
081: public void init(Query q) throws QueryParseException {
082:
083: // Load the class.
084: try {
085:
086: // Load via the custom (if present) classloader.
087: this .clazz = q.getClassLoader().loadClass(this .cn);
088:
089: } catch (Exception e) {
090:
091: throw new QueryParseException("Unable to load class: "
092: + this .cn, e);
093:
094: }
095:
096: Class[] conTypes = null;
097:
098: // Init all the constructor arg expressions, if provided.
099: if (this .constructorArgs != null) {
100:
101: conTypes = new Class[this .constructorArgs.size()];
102:
103: this .conParms = new Object[this .constructorArgs.size()];
104:
105: for (int i = 0; i < this .constructorArgs.size(); i++) {
106:
107: Expression exp = (Expression) this .constructorArgs
108: .get(i);
109:
110: exp.init(q);
111:
112: conTypes[i] = exp.getExpectedReturnType(q);
113:
114: }
115:
116: }
117:
118: TreeMap tm = new TreeMap();
119:
120: Constructor[] cons = this .clazz.getConstructors();
121:
122: for (int i = 0; i < cons.length; i++) {
123:
124: int score = Utilities.matchMethodArgs(cons[i]
125: .getParameterTypes(), conTypes);
126:
127: if (score > 0) {
128:
129: tm.put(Integer.valueOf(score), cons[i]);
130:
131: }
132:
133: }
134:
135: if (tm.size() > 0) {
136:
137: this .constructor = (Constructor) tm.get(tm.lastKey());
138:
139: }
140:
141: // Now try and find the constructor.
142: if (this .constructor == null) {
143:
144: throw new QueryParseException(
145: "Unable to find constructor: "
146: + Utilities.formatSignature(this .clazz
147: .getName(), conTypes));
148:
149: }
150:
151: // Now init any setters.
152: if (this .intoExps != null) {
153:
154: Iterator iter = this .intoExps.keySet().iterator();
155:
156: Class[] pts = new Class[1];
157:
158: while (iter.hasNext()) {
159:
160: Expression exp = (Expression) iter.next();
161:
162: String setName = (String) this .intoExps.get(exp);
163:
164: exp.init(q);
165:
166: pts[0] = exp.getExpectedReturnType(q);
167:
168: // Create the Setter.
169: Setter set = null;
170:
171: try {
172:
173: set = new Setter(setName, this .clazz, pts);
174:
175: } catch (Exception e) {
176:
177: throw new QueryParseException(
178: "Unable to create setter for: " + setName,
179: e);
180:
181: }
182:
183: this .intoExps.put(exp, set);
184:
185: }
186:
187: }
188:
189: }
190:
191: /**
192: * Always return <code>true</code> because a new object is being created and thus
193: * will be unequal to null.
194: *
195: * @param o The object currently in "scope".
196: * @param q The Query object.
197: * @return <code>true</code> always.
198: */
199: public boolean isTrue(Object o, Query q) {
200:
201: return true;
202:
203: }
204:
205: public Object evaluate(Object o, Query q)
206: throws QueryExecutionException {
207:
208: return this .getValue(o, q);
209:
210: }
211:
212: public Object getValue(Object o, Query q)
213: throws QueryExecutionException {
214:
215: // Need to create a new object.
216: if (this .constructorArgs != null) {
217:
218: for (int i = this .argsSize; i > -1; i--) {
219:
220: Expression exp = (Expression) this .constructorArgs
221: .get(i);
222:
223: try {
224:
225: this .conParms[i] = exp.getValue(o, q);
226:
227: } catch (Exception e) {
228:
229: throw new QueryExecutionException(
230: "Unable to evaluate constructor argument expression: "
231: + exp, e);
232:
233: }
234:
235: }
236:
237: }
238:
239: // Execute the constructor.
240: Object obj = null;
241:
242: try {
243:
244: obj = this .constructor.newInstance(Utilities
245: .convertArgs(this .conParms, this .constructor
246: .getParameterTypes()));
247:
248: } catch (Exception e) {
249:
250: throw new QueryExecutionException(
251: "Unable to create new instance of: "
252: + this .clazz.getName()
253: + " using constructor: " + this .constructor
254: + ", passing parameters: " + this .conParms,
255: e);
256:
257: }
258:
259: // See if we have any setters.
260: if (this .intoExps != null) {
261:
262: Iterator iter = this .intoExps.keySet().iterator();
263:
264: while (iter.hasNext()) {
265:
266: Expression exp = (Expression) iter.next();
267:
268: Setter set = (Setter) this .intoExps.get(exp);
269:
270: Object so = null;
271:
272: // Eval the expression.
273: try {
274:
275: so = exp.getValue(o, q);
276:
277: } catch (Exception e) {
278:
279: throw new QueryExecutionException(
280: "Unable to evaluate expression: " + exp
281: + " for setter: " + set
282: + " on class: "
283: + this .clazz.getName(), e);
284:
285: }
286:
287: try {
288:
289: set.setValue(obj, so);
290:
291: } catch (Exception e) {
292:
293: String cn = null + "";
294:
295: if (so != null) {
296:
297: cn = so.getClass().getName();
298:
299: }
300:
301: throw new QueryExecutionException(
302: "Unable to set value of type: "
303: + cn
304: + " in object of type: "
305: + this .clazz.getName()
306: + " using setter: "
307: + set
308: + " (value is result of expression: "
309: + exp + ")", e);
310:
311: }
312:
313: }
314:
315: }
316:
317: return obj;
318:
319: }
320:
321: public String toString() {
322:
323: StringBuffer b = new StringBuffer("new ");
324: b.append(this .clazz.getName());
325: b.append(" (");
326:
327: if (this .constructorArgs != null) {
328:
329: for (int i = 0; i < this .constructorArgs.size(); i++) {
330:
331: Expression exp = (Expression) this .constructorArgs
332: .get(i);
333:
334: b.append(exp);
335:
336: if (i < this .constructorArgs.size() - 1) {
337:
338: b.append(", ");
339:
340: }
341:
342: }
343:
344: }
345:
346: b.append(")");
347:
348: if (this .intoExps != null) {
349:
350: b.append(" {");
351:
352: Iterator iter = this .intoExps.keySet().iterator();
353:
354: while (iter.hasNext()) {
355:
356: Expression exp = (Expression) iter.next();
357:
358: b.append(exp);
359:
360: b.append(" -> ");
361:
362: Object obj = this .intoExps.get(exp);
363:
364: if (obj instanceof Setter) {
365:
366: Setter set = (Setter) obj;
367:
368: b.append(set);
369:
370: }
371:
372: if (obj instanceof String) {
373:
374: b.append((String) obj);
375:
376: }
377:
378: if (iter.hasNext()) {
379:
380: b.append(", ");
381:
382: }
383:
384: }
385:
386: b.append("}");
387:
388: }
389:
390: return b.toString();
391:
392: }
393:
394: }
|