EMMA Coverage Report (generated Sat Nov 03 21:53:04 GMT 2007)
[all classes][sf.qof.codegen]

COVERAGE SUMMARY FOR SOURCE FILE [InsertUpdateDeleteQueryMethodGenerator.java]

nameclass, %method, %block, %line, %
InsertUpdateDeleteQueryMethodGenerator.java100% (1/1)75%  (3/4)98%  (653/666)98%  (181/184)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class InsertUpdateDeleteQueryMethodGenerator100% (1/1)75%  (3/4)98%  (653/666)98%  (181/184)
InsertUpdateDeleteQueryMethodGenerator (): void 0%   (0/1)0%   (0/3)0%   (0/1)
addInsertUpdateDeleteQueryBodyNoCollection (CodeEmitter, QueryObjectGenerator... 100% (1/1)95%  (105/110)97%  (30/31)
addInsertUpdateDeleteQueryBodyWithCollection (CodeEmitter, QueryObjectGenerat... 100% (1/1)99%  (533/538)99%  (147/148)
addInsertUpdateDeleteQueryBody (CodeEmitter, QueryObjectGenerator, Mapper): void 100% (1/1)100% (15/15)100% (4/4)

1/*
2 * Copyright 2007 brunella ltd
3 *
4 * Licensed under the LGPL Version 3 (the "License");
5 * you may not use this file except in compliance with the License.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
11 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
12 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
14 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
15 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
16 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
17 * THE POSSIBILITY OF SUCH DAMAGE.
18 */
19package sf.qof.codegen;
20 
21import static sf.qof.codegen.Constants.EXCEPTION_COLLECTIONS_DIFFERENT_SIZE;
22import static sf.qof.codegen.Constants.FIELD_NAME_BATCH_SIZE;
23import static sf.qof.codegen.Constants.SIG_addBatch;
24import static sf.qof.codegen.Constants.SIG_arraycopy;
25import static sf.qof.codegen.Constants.SIG_executeBatch;
26import static sf.qof.codegen.Constants.SIG_executeUpdate;
27import static sf.qof.codegen.Constants.SIG_getConnection;
28import static sf.qof.codegen.Constants.SIG_hasNext;
29import static sf.qof.codegen.Constants.SIG_iterator;
30import static sf.qof.codegen.Constants.SIG_iterator_next;
31import static sf.qof.codegen.Constants.SIG_prepareStatement;
32import static sf.qof.codegen.Constants.SIG_size;
33import static sf.qof.codegen.Constants.TYPE_Collection;
34import static sf.qof.codegen.Constants.TYPE_Connection;
35import static sf.qof.codegen.Constants.TYPE_Iterator;
36import static sf.qof.codegen.Constants.TYPE_PreparedStatement;
37import static sf.qof.codegen.Constants.TYPE_SQLException;
38import static sf.qof.codegen.Constants.TYPE_System;
39import static sf.qof.codegen.Constants.TYPE_Throwable;
40import static sf.qof.codegen.Constants.TYPE_int;
41import static sf.qof.codegen.Constants.TYPE_intArray;
42import net.sf.cglib.core.Block;
43import net.sf.cglib.core.CodeEmitter;
44import net.sf.cglib.core.Local;
45 
46import org.objectweb.asm.Label;
47import org.objectweb.asm.Type;
48 
49import sf.qof.exception.ValidationException;
50import sf.qof.mapping.Mapper;
51import sf.qof.mapping.MethodParameterInfo;
52 
53/**
54 * Internal - InsertUpdateDeleteQueryMethodGenerator is the main generator class for insert, update and delete query methods.
55 */
56public class InsertUpdateDeleteQueryMethodGenerator {
57 
58  public static void addInsertUpdateDeleteQueryBody(CodeEmitter co, QueryObjectGenerator generator, Mapper mapper) {
59    if (mapper.getMethod().getCollectionParameterInfos().length > 0) {
60      addInsertUpdateDeleteQueryBodyWithCollection(co, generator, mapper);
61    } else {
62      addInsertUpdateDeleteQueryBodyNoCollection(co, generator, mapper);
63    }
64  }
65 
66  private static void addInsertUpdateDeleteQueryBodyNoCollection(CodeEmitter co, QueryObjectGenerator generator, Mapper mapper) {
67    Local localPreparedStatement = co.make_local(TYPE_PreparedStatement);
68    Local localException = co.make_local(TYPE_Throwable);
69  
70    // check for valid return type
71    Class<?> returnType = mapper.getMethod().getReturnInfo().getType();
72    if (returnType != Integer.TYPE && returnType != Void.TYPE) {
73                    throw new ValidationException("Only int or void is allowed as return type");
74            }
75    
76    // ps = connection.prepareStatement("select count(*) from person");
77    co.load_this();
78    co.invoke_virtual(Type.getType(generator.getClassNameType()), SIG_getConnection);
79    co.push(mapper.getSql());
80    co.invoke_interface(TYPE_Connection, SIG_prepareStatement);
81    co.store_local(localPreparedStatement);
82  
83    // try{
84    Block blockTry = co.begin_block();
85  
86    ParameterMappingGenerator pmg = new ParameterMappingGenerator(co, localPreparedStatement, null, null, null);
87    mapper.acceptParameterMappers(pmg);
88  
89    // ps.executeUpdate();
90    co.load_local(localPreparedStatement);
91    co.invoke_interface(TYPE_PreparedStatement, SIG_executeUpdate);
92    Local localResult = null;
93    if (returnType == Integer.TYPE) {
94      localResult = co.make_local(TYPE_int);
95      co.store_local(localResult);
96    } else {
97      co.pop();
98    }
99  
100    // finally block
101    EmitUtils.emitClose(co, localPreparedStatement, false);
102  
103    // return result
104    if (localResult != null) {
105      co.load_local(localResult);
106    }
107    co.return_value();
108    // }
109  
110    // exception handler + finally
111    blockTry.end();
112    co.catch_exception(blockTry, TYPE_Throwable);
113    // store thrown exception
114    co.store_local(localException);
115    // finally block
116    EmitUtils.emitClose(co, localPreparedStatement, false);
117    // throw stored exception
118    co.load_local(localException);
119    co.athrow();
120  }
121 
122  private static void addInsertUpdateDeleteQueryBodyWithCollection(CodeEmitter co, QueryObjectGenerator generator, Mapper mapper) {
123    MethodParameterInfo[] collectionParameterInfos = mapper.getMethod().getCollectionParameterInfos();
124    int numParameterCollections = collectionParameterInfos.length;
125  
126  
127    // check for valid return type
128    Class<?> returnType = mapper.getMethod().getReturnInfo().getType(); 
129    if (!(returnType == Void.TYPE) 
130      && !(returnType.isArray() && returnType.getComponentType() == Integer.TYPE)) {
131                    throw new ValidationException("Only int[] or void is allowed as return type");
132            }
133  
134    // check for different sizes
135    if (numParameterCollections > 1) {
136      Label labelException = co.make_label();
137      Label labelNoException = co.make_label();
138  
139      for (int i = 0; i < numParameterCollections - 1; i++) {
140        co.load_arg(collectionParameterInfos[i].getIndex());
141        co.invoke_interface(TYPE_Collection, SIG_size);
142        co.load_arg(collectionParameterInfos[i + 1].getIndex());
143        co.invoke_interface(TYPE_Collection, SIG_size);
144        co.if_icmp(CodeEmitter.NE, labelException);
145      }
146      co.goTo(labelNoException);
147  
148      co.mark(labelException);
149      co.throw_exception(TYPE_SQLException, EXCEPTION_COLLECTIONS_DIFFERENT_SIZE);
150  
151      co.mark(labelNoException);
152    }
153  
154    // if (parameter.size() == 0) return;
155    co.load_arg(collectionParameterInfos[0].getIndex());
156    co.invoke_interface(TYPE_Collection, SIG_size);
157    Label labelNotZero = co.make_label();
158    co.if_jump(CodeEmitter.NE, labelNotZero);
159    if (returnType.isArray()) {
160            // push new int[0]
161            co.push(0);
162            co.newarray(TYPE_int);
163    }
164    co.return_value();
165    co.mark(labelNotZero);
166  
167    Local localPreparedStatement = co.make_local(TYPE_PreparedStatement);
168    Local localException = co.make_local(TYPE_Throwable);
169  
170    // ps = connection.prepareStatement("select count(*) from person");
171    co.load_this();
172    co.invoke_virtual(Type.getType(generator.getClassNameType()), SIG_getConnection);
173    co.push(mapper.getSql());
174    co.invoke_interface(TYPE_Connection, SIG_prepareStatement);
175    co.store_local(localPreparedStatement);
176  
177    // try{
178    Block blockTry = co.begin_block();
179  
180    Local localResult = null;
181    Local localPartResult = null;
182    Local localIndex = null;
183    
184    if (returnType.isArray()) {
185            // result = new int[collection.size()];
186            localResult = co.make_local(TYPE_intArray);
187            localPartResult = co.make_local(TYPE_intArray);
188            co.load_arg(collectionParameterInfos[0].getIndex());
189            co.invoke_interface(TYPE_Collection, SIG_size);
190            co.newarray(TYPE_int);
191            co.store_local(localResult);
192            // int index = 0;
193            localIndex = co.make_local(TYPE_int);
194            co.push(0);
195            co.store_local(localIndex);
196    }
197  
198    // start the loop
199    // Iterator<Person> iter = list.iterator();
200    // int i = 0;
201    // while (iter.hasNext()) {
202    // Person person = iter.next();
203    // i++;
204    Local localCounter = co.make_local(TYPE_int);
205    co.push(0);
206    co.store_local(localCounter);
207  
208    Local[] localIterators = new Local[numParameterCollections];
209    Local[] localObjects = new Local[numParameterCollections];
210    for (int i = 0; i < numParameterCollections; i++) {
211      localIterators[i] = co.make_local(TYPE_Iterator);
212      co.load_arg(collectionParameterInfos[i].getIndex());
213      co.invoke_interface(TYPE_Collection, SIG_iterator);
214      co.store_local(localIterators[i]);
215  
216      localObjects[i] = co.make_local(Type.getType(collectionParameterInfos[i].getCollectionElementType()));
217    }
218  
219    // while
220    Label labelBeginWhile = co.make_label();
221    Label labelEndWhile = co.make_label();
222    co.mark(labelBeginWhile);
223    co.load_local(localIterators[0]);
224    co.invoke_interface(TYPE_Iterator, SIG_hasNext);
225    co.if_jump(CodeEmitter.EQ, labelEndWhile);
226  
227    for (int i = 0; i < numParameterCollections; i++) {
228      co.load_local(localIterators[i]);
229      co.invoke_interface(TYPE_Iterator, SIG_iterator_next);
230      co.checkcast(Type.getType(collectionParameterInfos[i].getCollectionElementType()));
231      co.store_local(localObjects[i]);
232    }
233    co.iinc(localCounter, 1);
234  
235    ParameterMappingGenerator pmg = new ParameterMappingGenerator(co, localPreparedStatement, localObjects,
236        collectionParameterInfos, null);
237    mapper.acceptParameterMappers(pmg);
238  
239    // if (batchSize > 0) {
240    // ps.addBatch();
241    // if (i >= batchSize) {
242    // ps.executeBatch();
243    // i = 0;
244    // }
245    // } else {
246    // ps.execute();
247    // }
248    co.load_this();
249    co.getfield(FIELD_NAME_BATCH_SIZE);
250    Label labelNoBatching = co.make_label();
251    co.if_jump(CodeEmitter.LE, labelNoBatching);
252  
253    co.load_local(localPreparedStatement);
254    co.invoke_interface(TYPE_PreparedStatement, SIG_addBatch);
255  
256    // if (i >= batchSize) {
257    // ps.executeBatch();
258    // i = 0;
259    // }
260    co.load_local(localCounter);
261    co.load_this();
262    co.getfield(FIELD_NAME_BATCH_SIZE);
263    Label labelAfter = co.make_label();
264    co.if_icmp(CodeEmitter.LT, labelAfter);
265  
266    co.load_local(localPreparedStatement);
267    co.invoke_interface(TYPE_PreparedStatement, SIG_executeBatch);
268    if (returnType.isArray()) {
269            co.store_local(localPartResult);
270            // System.arraycopy(partResult, 0, result, index, partResult.length);
271            co.load_local(localPartResult);
272            co.push(0);
273            co.load_local(localResult);
274            co.load_local(localIndex);
275            co.load_local(localPartResult);
276            co.arraylength();
277            co.invoke_static(TYPE_System, SIG_arraycopy);
278  
279            // index += partResult.length;
280            co.load_local(localIndex);
281            co.load_local(localPartResult);
282            co.arraylength();
283            co.math(CodeEmitter.ADD, TYPE_int);
284            co.store_local(localIndex);
285  
286    } else {
287            co.pop();
288    }
289    co.push(0);
290    co.store_local(localCounter);
291  
292    co.mark(labelAfter);
293  
294    co.goTo(labelBeginWhile);
295  
296    co.mark(labelNoBatching);
297  
298    if (returnType.isArray()) {
299            // result[index++] = ps.executeUpdate();
300            co.load_local(localResult);
301            co.load_local(localIndex);
302            co.iinc(localIndex, 1);
303            co.load_local(localPreparedStatement);
304            co.invoke_interface(TYPE_PreparedStatement, SIG_executeUpdate);
305            co.array_store(TYPE_int);
306    } else {
307            co.load_local(localPreparedStatement);
308            co.invoke_interface(TYPE_PreparedStatement, SIG_executeUpdate);
309            co.pop();
310    }
311  
312    co.goTo(labelBeginWhile);
313  
314    co.mark(labelEndWhile);
315  
316    // if (batchSize > 0 && i > 0) {
317    // ps.executeBatch();
318    // }
319    Label labelAfter2 = co.make_label();
320    co.load_local(localCounter);
321    co.if_jump(CodeEmitter.LE, labelAfter2);
322    co.load_this();
323    co.getfield(FIELD_NAME_BATCH_SIZE);
324    co.if_jump(CodeEmitter.LE, labelAfter2);
325  
326    co.load_local(localPreparedStatement);
327    co.invoke_interface(TYPE_PreparedStatement, SIG_executeBatch);
328    if (returnType.isArray()) {
329            co.store_local(localPartResult);
330            // System.arraycopy(partResult, 0, result, index, partResult.length);
331            co.load_local(localPartResult);
332            co.push(0);
333            co.load_local(localResult);
334            co.load_local(localIndex);
335            co.load_local(localPartResult);
336            co.arraylength();
337            co.invoke_static(TYPE_System, SIG_arraycopy);
338    } else {
339            co.pop();
340    }
341  
342    co.mark(labelAfter2);
343  
344    // finally block
345    EmitUtils.emitClose(co, localPreparedStatement, false);
346  
347    // return result
348    if (returnType.isArray()) {
349            co.load_local(localResult);
350    }
351    co.return_value();
352    // }
353  
354    // exception handler + finally
355    blockTry.end();
356    co.catch_exception(blockTry, TYPE_Throwable);
357    // store thrown exception
358    co.store_local(localException);
359    // finally block
360    EmitUtils.emitClose(co, localPreparedStatement, false);
361    // throw stored exception
362    co.load_local(localException);
363    co.athrow();
364  }
365 
366}

[all classes][sf.qof.codegen]
EMMA 2.0.5312 (C) Vladimir Roubtsov