| 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 | } |