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 | */ |
19 | package sf.qof; |
20 | |
21 | import java.lang.reflect.Method; |
22 | import java.lang.reflect.Modifier; |
23 | import java.util.ArrayList; |
24 | import java.util.List; |
25 | |
26 | import sf.qof.adapter.CommonAdapterRegistrar; |
27 | import sf.qof.codegen.AnnotationMapperFactory; |
28 | import sf.qof.codegen.QueryObjectGenerator; |
29 | import sf.qof.customizer.Customizer; |
30 | import sf.qof.customizer.DefaultCustomizer; |
31 | import sf.qof.dialect.DefaultDialect; |
32 | import sf.qof.dialect.SQLDialect; |
33 | import sf.qof.mapping.Mapper; |
34 | import sf.qof.mapping.MappingAdapter; |
35 | import sf.qof.mapping.MappingFactory; |
36 | import sf.qof.util.ClassGenerationCache; |
37 | import 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 | * @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 | */ |
90 | public 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 | } |