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

COVERAGE SUMMARY FOR SOURCE FILE [BooleanAdapter.java]

nameclass, %method, %block, %line, %
BooleanAdapter.java100% (1/1)91%  (10/11)92%  (640/696)92%  (179/195)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class BooleanAdapter100% (1/1)91%  (10/11)92%  (640/696)92%  (179/195)
getNumberOfColumns (): int 0%   (0/1)0%   (0/2)0%   (0/1)
BooleanAdapter (String, String, String, boolean, boolean): void 100% (1/1)80%  (20/25)89%  (8/9)
generateToPreparedStatement (ParameterMapping, CodeEmitter, Local, int [], Lo... 100% (1/1)85%  (279/328)85%  (80/94)
<static initializer> 100% (1/1)100% (25/25)100% (6/6)
emitProcessResult (ResultMapping, CodeEmitter): void 100% (1/1)100% (245/245)100% (65/65)
generateFromResult (ResultMapping, CodeEmitter, Local, int []): void 100% (1/1)100% (18/18)100% (5/5)
generateFromResultSet (ResultMapping, CodeEmitter, Local, String []): void 100% (1/1)100% (17/17)100% (5/5)
generateRegisterOutputParameters (ResultMapping, CodeEmitter, Local, int []):... 100% (1/1)100% (16/16)100% (5/5)
getTypes (): Set 100% (1/1)100% (2/2)100% (1/1)
register (String, String, String, boolean, boolean): void 100% (1/1)100% (11/11)100% (2/2)
registerYesNo (): void 100% (1/1)100% (7/7)100% (2/2)

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.adapter;
20 
21import static sf.qof.codegen.Constants.SIG_Boolean_valueOf;
22import static sf.qof.codegen.Constants.SIG_booleanValue;
23import static sf.qof.codegen.Constants.SIG_getString;
24import static sf.qof.codegen.Constants.SIG_getStringNamed;
25import static sf.qof.codegen.Constants.SIG_registerOutParameter;
26import static sf.qof.codegen.Constants.SIG_setNull;
27import static sf.qof.codegen.Constants.SIG_setString;
28import static sf.qof.codegen.Constants.TYPE_Boolean;
29import static sf.qof.codegen.Constants.TYPE_CallableStatement;
30import static sf.qof.codegen.Constants.TYPE_PreparedStatement;
31import static sf.qof.codegen.Constants.TYPE_ResultSet;
32import static sf.qof.codegen.Constants.TYPE_SQLException;
33import static sf.qof.codegen.Constants.TYPE_String;
34import static sf.qof.codegen.Constants.TYPE_boolean;
35import static sf.qof.codegen.Constants.TYPE_int;
36 
37import java.util.HashSet;
38import java.util.Set;
39 
40import net.sf.cglib.core.CodeEmitter;
41import net.sf.cglib.core.Local;
42import net.sf.cglib.core.Signature;
43 
44import org.objectweb.asm.Label;
45import org.objectweb.asm.Type;
46 
47import sf.qof.QueryObjectFactory;
48import sf.qof.mapping.ParameterMapping;
49import sf.qof.mapping.ResultMapping;
50 
51/**
52 * BooleanAdapter is a generator mapping adapter for boolean data types.
53 * 
54 * <p>It maps <code>VARCHAR</code> columns to <code>boolean</code> and <code>Boolean</code> and vice versa.</p>
55 *
56 * <p>Examples:</p>
57 * <pre><blockquote>
58 *   (1) BooleanAdapter.register("yesno", "Y", "N", false, true);
59 *   
60 *   (2) BooleanAdapter.register("true-false", "true", "false", true, false);
61 *   
62 *   (3) BooleanAdapter.register("bigX", "X", null, true, true);
63 * </blockquote></pre>
64 * 
65 * <p>(1) Maps boolean types to "Y" and "N", is not case-sensitive ("y" is true as well)
66 * and allows null values (a SQL null value gets mapped to <code>false</code> if the 
67 * type is <code>boolean</code>).</p>
68 * 
69 * <p>(2) Maps boolean types to the strings "true" and "false", is case-sensitive and
70 * does not allow null values.</p>
71 * 
72 * <p>(3) Maps boolean types to "X" and null, is case-sensitive and allows nulls.</p>
73 * 
74 * @see #registerYesNo()
75 * @see #register(String, String, String, boolean, boolean)
76 */
77public class BooleanAdapter implements GeneratorMappingAdapter {
78 
79  private final static Signature SIG_toUpperCase = new Signature("toUpperCase", "()Ljava/lang/String;");
80  private final static Signature SIG_equals = new Signature("equals", "(Ljava/lang/Object;)Z");
81  
82  private String typeName;
83  private String trueString;
84  private String falseString;
85  private boolean caseSensitive;
86  private boolean allowNull;
87 
88  private BooleanAdapter(String typeName, String trueString, String falseString, boolean caseSensitive, boolean allowNull) {
89    if (trueString == null) {
90      throw new IllegalArgumentException("trueString must not be null");
91    }
92    this.typeName = typeName;
93    this.trueString = trueString;
94    this.falseString = falseString;
95    this.caseSensitive = caseSensitive;
96    this.allowNull = allowNull;
97  }
98  
99  public void generateFromResult(ResultMapping resultMapping, CodeEmitter co, Local result, int[] indexes) {
100    co.load_local(result);
101    co.push(indexes[0]);
102    co.invoke_interface(result.getType(), SIG_getString);
103    emitProcessResult(resultMapping, co);
104  }
105 
106  public void generateFromResultSet(ResultMapping resultMapping, CodeEmitter co, Local resultSet, String[] columns) {
107    co.load_local(resultSet);
108    co.push(columns[0]);
109    co.invoke_interface(TYPE_ResultSet, SIG_getStringNamed);
110    emitProcessResult(resultMapping, co);
111  }
112 
113  private void emitProcessResult(ResultMapping resultMapping, CodeEmitter co) {
114    Label labelNull = co.make_label();
115    Label labelNotFalse = co.make_label();
116    Label labelEnd = co.make_label();
117    Local localString = co.make_local(TYPE_String);
118    Local localTrueFalse = co.make_local(TYPE_boolean);
119    Local localResult = null;
120    if (resultMapping.getType() == Boolean.class) {
121      localResult = co.make_local(TYPE_Boolean);
122    }
123    co.store_local(localString);
124    co.load_local(localString);
125    co.ifnull(labelNull);
126    // not null
127    co.load_local(localString);
128    if (!caseSensitive) {
129      co.invoke_virtual(TYPE_String, SIG_toUpperCase);
130      co.push(trueString.toUpperCase());
131    } else {
132      co.push(trueString);
133    }
134    co.invoke_virtual(Type.getType(Object.class), SIG_equals);
135    co.store_local(localTrueFalse);
136    if (falseString != null) {
137      co.load_local(localTrueFalse);
138      co.if_jump(CodeEmitter.NE, labelNotFalse);
139      co.load_local(localString);
140      if (!caseSensitive) {
141        co.invoke_virtual(TYPE_String, SIG_toUpperCase);
142        co.push(falseString.toUpperCase());
143      } else {
144        co.push(falseString);
145      }
146      co.invoke_virtual(Type.getType(Object.class), SIG_equals);
147      // negate result
148      Label labelIsFalse = co.make_label();
149      Label labelIsTrueFalseEnd = co.make_label();
150      
151      co.if_jump(CodeEmitter.EQ, labelIsFalse);
152      co.push(false);
153      co.goTo(labelIsTrueFalseEnd);
154      co.mark(labelIsFalse);
155      co.push(true);
156      co.mark(labelIsTrueFalseEnd);
157      
158      co.store_local(localTrueFalse);
159      co.load_local(localTrueFalse);
160      co.if_jump(CodeEmitter.EQ, labelNotFalse);
161      co.throw_exception(TYPE_SQLException, "invalid value for mapper \"" + typeName + "\"");
162      co.mark(labelNotFalse);
163    }
164    if (resultMapping.getType() == Boolean.class) {
165      co.load_local(localTrueFalse);
166      co.invoke_static(TYPE_Boolean, SIG_Boolean_valueOf);
167      co.store_local(localResult);
168    }
169    
170    co.goTo(labelEnd);
171 
172    co.mark(labelNull);
173    // null
174    if (falseString != null) {
175      if (allowNull) {
176        if (resultMapping.getType() == Boolean.class) {
177          co.aconst_null();
178          co.store_local(localResult);
179        } else {
180          co.push(false);
181          co.store_local(localTrueFalse);
182        }
183      } else {
184        co.throw_exception(TYPE_SQLException, "null value not allowed for mapper \"" + typeName + "\"");
185      }
186    } else {
187      if (resultMapping.getType() == Boolean.class) {
188        co.push(false);
189        co.invoke_static(TYPE_Boolean, SIG_Boolean_valueOf);
190        co.store_local(localResult);
191      } else {
192        co.push(false);
193        co.store_local(localTrueFalse);
194      }
195    }
196    co.mark(labelEnd);
197    if (resultMapping.getType() == Boolean.class) {
198      co.load_local(localResult);
199    } else {
200      co.load_local(localTrueFalse);
201    }
202  }
203 
204  public void generateToPreparedStatement(ParameterMapping parameterMapping, CodeEmitter co, Local preparedStatement, int[] indexes, Local indexOffset) {
205    Label labelFalse = co.make_label();
206    Label labelTrueFalseEnd = co.make_label();
207    if (parameterMapping.getType() == Boolean.class) {
208      // Boolean type
209      Local localBoolean = co.make_local(TYPE_Boolean);
210      co.store_local(localBoolean);
211      co.load_local(localBoolean);
212      Label labelNull = co.make_label();
213      Label labelEnd = co.make_label();
214      co.ifnull(labelNull);
215      // not null
216      if (falseString != null) {
217        co.load_local(preparedStatement);
218        co.push(indexes[0]);
219        if (indexOffset != null) {
220          co.load_local(indexOffset);
221          co.math(CodeEmitter.ADD, TYPE_int);
222        }
223        co.load_local(localBoolean);
224        co.invoke_virtual(TYPE_Boolean, SIG_booleanValue);
225        co.if_jump(CodeEmitter.EQ, labelFalse);
226        // true
227        co.push(trueString);
228        co.goTo(labelTrueFalseEnd);
229        //false
230        co.mark(labelFalse);
231        co.push(falseString);
232        co.mark(labelTrueFalseEnd);
233        co.invoke_interface(TYPE_PreparedStatement, SIG_setString);
234        co.goTo(labelEnd);
235      } else {
236        co.load_local(localBoolean);
237        co.invoke_virtual(TYPE_Boolean, SIG_booleanValue);
238        co.if_jump(CodeEmitter.EQ, labelFalse);
239        // true
240        co.load_local(preparedStatement);
241        co.push(indexes[0]);
242        if (indexOffset != null) {
243          co.load_local(indexOffset);
244          co.math(CodeEmitter.ADD, TYPE_int);
245        }
246        co.push(trueString);
247        co.invoke_interface(TYPE_PreparedStatement, SIG_setString);
248        co.goTo(labelTrueFalseEnd);
249        //false
250        co.mark(labelFalse);
251        co.load_local(preparedStatement);
252        co.push(indexes[0]);
253        if (indexOffset != null) {
254          co.load_local(indexOffset);
255          co.math(CodeEmitter.ADD, TYPE_int);
256        }
257        co.push(java.sql.Types.VARCHAR);
258        co.invoke_interface(TYPE_PreparedStatement, SIG_setNull);
259        
260        co.mark(labelTrueFalseEnd);
261        co.goTo(labelEnd);
262      }
263      
264      co.mark(labelNull);
265      // null
266      if (allowNull) {
267        co.load_local(preparedStatement);
268        co.push(indexes[0]);
269        if (indexOffset != null) {
270          co.load_local(indexOffset);
271          co.math(CodeEmitter.ADD, TYPE_int);
272        }
273        co.push(java.sql.Types.VARCHAR);
274        co.invoke_interface(TYPE_PreparedStatement, SIG_setNull);
275      } else {
276        co.throw_exception(TYPE_SQLException, "null value not allowed for mapper \"" + typeName + "\"");
277      }
278      co.mark(labelEnd);
279    } else {
280      // boolean type
281      Local localBoolean = co.make_local(TYPE_boolean);
282      co.store_local(localBoolean);
283      if (falseString != null) {
284        co.load_local(preparedStatement);
285        co.push(indexes[0]);
286        if (indexOffset != null) {
287          co.load_local(indexOffset);
288          co.math(CodeEmitter.ADD, TYPE_int);
289        }
290        co.load_local(localBoolean);
291        co.if_jump(CodeEmitter.EQ, labelFalse);
292        // true
293        co.push(trueString);
294        co.goTo(labelTrueFalseEnd);
295        //false
296        co.mark(labelFalse);
297        co.push(falseString);
298        
299        co.mark(labelTrueFalseEnd);
300        co.invoke_interface(TYPE_PreparedStatement, SIG_setString);
301      } else {
302        co.load_local(localBoolean);
303        co.if_jump(CodeEmitter.EQ, labelFalse);
304        // true
305        co.load_local(preparedStatement);
306        co.push(indexes[0]);
307        if (indexOffset != null) {
308          co.load_local(indexOffset);
309          co.math(CodeEmitter.ADD, TYPE_int);
310        }
311        co.push(trueString);
312        co.invoke_interface(TYPE_PreparedStatement, SIG_setString);
313        co.goTo(labelTrueFalseEnd);
314        //false
315        co.mark(labelFalse);
316        co.load_local(preparedStatement);
317        co.push(indexes[0]);
318        if (indexOffset != null) {
319          co.load_local(indexOffset);
320          co.math(CodeEmitter.ADD, TYPE_int);
321        }
322        co.push(java.sql.Types.VARCHAR);
323        co.invoke_interface(TYPE_PreparedStatement, SIG_setNull);
324        co.mark(labelTrueFalseEnd);
325      }
326    }
327  }
328 
329  public void generateRegisterOutputParameters(ResultMapping resultMapping, CodeEmitter co, Local callableStatement,
330      int[] indexes) {
331    co.load_local(callableStatement);
332    co.push(indexes[0]);
333    co.push(java.sql.Types.VARCHAR);
334    co.invoke_interface(TYPE_CallableStatement, SIG_registerOutParameter);
335  }
336 
337  public int getNumberOfColumns() {
338    return 1;
339  }
340 
341  public Set<Class<?>> getTypes() {
342    return typeSet;
343  }
344 
345  private static Set<Class<?>> typeSet;
346  
347  static {
348    typeSet = new HashSet<Class<?>>();
349    typeSet.add(boolean.class);
350    typeSet.add(Boolean.class);
351  }
352  
353  /**
354   * Registers a yes/no adapter with name "yesno".
355   * 
356   * It maps "Y" to true, "N" to false, is not case-sensitive and allows null values.
357   */
358  public static void registerYesNo() {
359    register("yesno", "Y", "N", false, true);
360  }
361  
362  /**
363   * Registers a <code>BooleanAdapter</code> with a given name.
364   * 
365   * @param typeName       the type name to be used in parameter and result definitions
366   * @param trueString     a string representing the true value
367   * @param falseString    a string representing the false value. Can be null
368   * @param caseSensitive  true if the mapping is case-sensitive
369   * @param allowNull      true if null values are allowed
370   */
371  public static void register(String typeName, String trueString, String falseString, boolean caseSensitive, boolean allowNull) {
372    QueryObjectFactory.registerMapper(typeName, new BooleanAdapter(typeName, trueString, falseString, caseSensitive, allowNull));
373  }
374  
375}

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