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

COVERAGE SUMMARY FOR SOURCE FILE [QueryObjectFactory.java]

nameclass, %method, %block, %line, %
QueryObjectFactory.java100% (1/1)91%  (10/11)98%  (167/170)98%  (41/42)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class QueryObjectFactory100% (1/1)91%  (10/11)98%  (167/170)98%  (41/42)
QueryObjectFactory (): void 0%   (0/1)0%   (0/3)0%   (0/1)
<static initializer> 100% (1/1)100% (12/12)100% (5/5)
createQueryObject (Class): Object 100% (1/1)100% (5/5)100% (1/1)
createQueryObject (Class, Object []): Object 100% (1/1)100% (13/13)100% (3/3)
createQueryObjectFromSuperClass (Class, Class): Object 100% (1/1)100% (6/6)100% (1/1)
createQueryObjectFromSuperClass (Class, Class, Object []): Object 100% (1/1)100% (115/115)100% (21/21)
registerMapper (String, MappingAdapter): void 100% (1/1)100% (4/4)100% (2/2)
setCustomizer (Customizer): void 100% (1/1)100% (3/3)100% (2/2)
setDefaultCustomizer (): void 100% (1/1)100% (3/3)100% (2/2)
setSQLDialect (SQLDialect): void 100% (1/1)100% (3/3)100% (2/2)
unregisterMapper (String): void 100% (1/1)100% (3/3)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;
20 
21import java.lang.reflect.Method;
22import java.lang.reflect.Modifier;
23import java.util.ArrayList;
24import java.util.List;
25 
26import sf.qof.adapter.CommonAdapterRegistrar;
27import sf.qof.codegen.AnnotationMapperFactory;
28import sf.qof.codegen.QueryObjectGenerator;
29import sf.qof.customizer.Customizer;
30import sf.qof.customizer.DefaultCustomizer;
31import sf.qof.dialect.DefaultDialect;
32import sf.qof.dialect.SQLDialect;
33import sf.qof.mapping.Mapper;
34import sf.qof.mapping.MappingAdapter;
35import sf.qof.mapping.MappingFactory;
36import sf.qof.util.ClassGenerationCache;
37import sf.qof.util.ObjectInstantiator;
38 
39/**
40 * Used to create query object implementations from definition interfaces or classes. 
41 * It only provides static methods and can not be instantiated. 
42 *
43 * <p> Definition interfaces or classes define abstract methods that are decorated 
44 * with annotations to specify the SQL query and mappings to primitive types or 
45 * Java beans.</p>
46 *
47 * <p><blockquote><pre>
48 *     public class Person {
49 *         int id;
50 *         String name;
51 *         
52 *         public int getId() {
53 *             return id;
54 *         }
55 *         public void setId(int id) {
56 *             this.id = id;
57 *         }
58 *         ...
59 *     }
60 *     
61 *     public interface PersonQueries extends BaseQuery {
62 *         &#64;Query(sql = "select id {%%.id}, name {%%.name} from person where id = {%1}")
63 *         Person getPerson(int id);
64 *         ...
65 *     }
66 *     
67 *     Connection connection = ... // get the database connection from somewhere
68 *     PersonQueries personQueries = <b>QueryObjectFactory.createQueryObject(PersonQueries.class);</b>
69 *     personQueries.setConnection(connection);
70 *     Person person = personQueries.getPerson(123);
71 * </pre></blockquote></p>
72 * 
73 * <p> Generated query object classes implement <code>BaseQuery</code> to set the 
74 * connection etc.</p>
75 * 
76 * <p> Generated query object classes are cached for each ClassLoader. The generation
77 * process is thread safe i.e. if two threads are trying to create the same query object 
78 * implementation one will wait till the generation of the class completes and then
79 * just instantiate an object while the other thread is generating the class.</p>
80 * 
81 * <p> The generation process can be customized by using a <code>Customizer</code></p>
82 *
83 * @see BaseQuery
84 * @see Query
85 * @see Insert
86 * @see Update
87 * @see Delete
88 * @see Call
89 */
90public final class QueryObjectFactory {
91 
92  private QueryObjectFactory() { }
93  
94  private static final Customizer DEFAULT_CUSTOMIZER = new DefaultCustomizer(); 
95  private static Customizer customizer = DEFAULT_CUSTOMIZER;
96  private static SQLDialect sqlDialect = new DefaultDialect();
97 
98  /**
99   * Creates a query object class defined by a query definition and returns a new instance. 
100   * 
101   * <p> If the query definition is a class then the generated query object class will be
102   * a subclass of this class. The query definition class can be abstract or concrete but 
103   * is not allowed to be final. All constructors of the query definition class will be 
104   * implemented by the query object class but only the default constructor will be used
105   * to instantiate the query object.
106   * 
107   * <p>If the query definition is an interface then the superclass will be <code>Object</code>.
108   *
109   * @param queryDefinitionClass query definition class or interface
110   * @return an instance that implements the abstract definitions defined in <code>queryDefinitionClass</code>
111   * 
112   * @see sf.qof.QueryObjectFactory#createQueryObject(Class, Object...)
113   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class)
114   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class, Object...)
115   * 
116   * @since 1.0
117   */
118  public static <T> T createQueryObject(Class<T> queryDefinitionClass) {
119    return createQueryObject(queryDefinitionClass, new Object[] {});
120  }
121 
122  /**
123   * Creates a query object class defined by a query definition and returns a new instance.
124   * 
125   * <p> The generated query object class is a subclass of query definition class. The
126   * query definition class can be abstract or concrete but is not allowed to be final.
127   * All constructors of the query definition class will be implemented by the query object
128   * class and <code>parameters</code> will be used to find a matching constructor to instantiate
129   * the query object with these parameters. The matching process works on the type of
130   * the parameters and will match the first constructor that matches all parameter type.
131   * 
132   * <p> A single <code>null</code> parameter should be passed to a constructor as:
133   * <code>new Class[] {null}</code>.
134   * 
135   * @param queryDefinitionClass query definition class
136   * @param parameters parameters to be used in the constructor
137   * @return an instance that implements the abstract definitions defined in <code>queryDefinitionClass</code>
138   * 
139   * @see sf.qof.QueryObjectFactory#createQueryObject(Class)
140   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class)
141   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class, Object...)
142   * 
143   * @since 1.0
144   */
145  public static <T> T createQueryObject(Class<T> queryDefinitionClass, Object... parameters) {
146    if (queryDefinitionClass.isInterface()) {
147      return (T) createQueryObjectFromSuperClass(queryDefinitionClass, Object.class, parameters);
148    } else {
149      return (T) createQueryObjectFromSuperClass(queryDefinitionClass, queryDefinitionClass, parameters);
150    }
151  }
152 
153  /**
154   * Creates a query object class defined by a query definition and a super class and returns a new instance. 
155   * 
156   * <p> The generated query object class will be a subclass of <code>superClass</code>
157   * which can be abstract or concrete but is not allowed to be final. 
158   * All constructors of <code>superClass</code> will be implemented by the query object 
159   * class but only the default constructor will be used to instantiate the query object.
160   * 
161   * <p><code>queryDefinitionClass</code> must be an interface.
162   *
163   * @param queryDefinitionClass query definition interface
164   * @param superClass the class the query object class will inherit from
165   * @return an instance that implements the abstract definitions defined in <code>queryDefinitionClass</code>
166   * 
167   * @see sf.qof.QueryObjectFactory#createQueryObject(Class)
168   * @see sf.qof.QueryObjectFactory#createQueryObject(Class, Object...)
169   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class, Object...)
170   * 
171   * @since 1.0
172   */
173  public static <T, S> T createQueryObjectFromSuperClass(Class<T> queryDefinitionClass, Class<S> superClass) {
174    return createQueryObjectFromSuperClass(queryDefinitionClass, superClass, new Object[] {});
175  }
176 
177  /**
178   * Creates a query object class defined by a query definition and a super class and returns a new instance. 
179   * 
180   * <p> The generated query object class will be a subclass of <code>superClass</code> 
181   * which can be abstract or concrete but is not allowed to be final. 
182   * All constructors of <code>superClass</code> will be implemented by the query object class
183   * and <code>parameters</code> will be used to find a matching constructor to instantiate
184   * the query object with these parameters. The matching process works on the type of
185   * the parameters and will match the first constructor that matches all parameter type.
186   * 
187   * <p> A single <code>null</code> parameter should be passed to a constructor as:
188   * <code>new Class[] {null}</code>.
189   * 
190   * <p><code>queryDefinitionClass</code> must be an interface.
191   *
192   * @param queryDefinitionClass query definition interface
193   * @param superClass the class the query object class will inherit from
194   * @param parameters parameters to be used in the constructor
195   * @return an instance that implements the abstract definitions defined in <code>queryDefinitionClass</code>
196   * 
197   * @see sf.qof.QueryObjectFactory#createQueryObject(Class)
198   * @see sf.qof.QueryObjectFactory#createQueryObject(Class, Object...)
199   * @see sf.qof.QueryObjectFactory#createQueryObjectFromSuperClass(Class, Class)
200   * 
201   * @since 1.0
202   */
203  @SuppressWarnings("unchecked")
204  public static <T, S> T createQueryObjectFromSuperClass(Class<T> queryDefinitionClass, Class<S> superClass,
205      Object... parameters) {
206    if ((queryDefinitionClass != superClass) && !queryDefinitionClass.isInterface()) {
207      throw new RuntimeException("Invalid class hierarchie");
208    }
209    Class<T> clazz = (Class<T>)ClassGenerationCache.getCachedClass(queryDefinitionClass);
210    if (clazz == null) {
211      try {
212        List<Mapper> mappers = new ArrayList<Mapper>();
213        // get all public methods
214        for (Method method : queryDefinitionClass.getMethods()) {
215          Mapper mapper = AnnotationMapperFactory.create(method);
216          if (mapper != null) {
217                mappers.add(mapper);
218          }
219        }
220        // get all protected methods
221        for (Method method : queryDefinitionClass.getDeclaredMethods()) {
222          if (Modifier.isProtected(method.getModifiers())) {
223            Mapper mapper = AnnotationMapperFactory.create(method);
224            if (mapper != null) {
225              mappers.add(mapper);
226            }
227          }
228        }
229        clazz = new QueryObjectGenerator(customizer, sqlDialect).create(queryDefinitionClass, mappers, superClass);
230        // put the newly created class
231        ClassGenerationCache.putCachedClass(clazz, queryDefinitionClass);
232      } catch (RuntimeException e) {
233        ClassGenerationCache.putCachedClass(null, queryDefinitionClass);
234        throw e;
235      }
236    }
237    return ObjectInstantiator.newInstance(clazz, parameters);
238  }
239 
240  /**
241   * Sets the <code>Customizer</code> for the code generation.
242   * 
243   * @param cust a customizer
244   * 
245   * @see sf.qof.customizer.Customizer
246   */
247  public static void setCustomizer(Customizer cust) {
248    customizer = cust;
249  }
250 
251  /**
252   * Resets the <code>Customizer</code> for the code generation to the default customizer.
253   * 
254   * @see sf.qof.customizer.Customizer
255   * @see sf.qof.customizer.DefaultCustomizer
256   */
257  public static void setDefaultCustomizer() {
258    customizer = DEFAULT_CUSTOMIZER;
259  }
260  
261  /**
262   * Register a custom mapping adapter in the mapping registry.
263   * 
264   * <p> This method can be used to register custom mapping adapters. 
265   * 
266   * @param type        mapping type name
267   * @param adapter     mapping adapter
268   * 
269   * @see sf.qof.adapter.GeneratorMappingAdapter
270   * @see sf.qof.adapter.DynamicMappingAdapter
271   * @see sf.qof.mapping.MappingAdapter
272   */
273  public static void registerMapper(String type, MappingAdapter adapter) {
274    MappingFactory.registerMapper(type, adapter);
275  }
276 
277  /**
278   * Unregister a custom mapping adapter from the mapping registry.
279   * 
280   * @param type        mapping type name
281   */
282  public static void unregisterMapper(String type) {
283    MappingFactory.unregisterMapper(type);
284  }
285  
286  /**
287   * Sets the SQL dialect.
288   * 
289   * @param dialect    SQL dialect
290   * 
291   * @see sf.qof.dialect.SQLDialect
292   */
293  public static void setSQLDialect(SQLDialect dialect) {
294    sqlDialect = dialect;
295  }
296  
297  static {
298    CommonAdapterRegistrar.registerCommonAdapters();
299  }
300}

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