View Javadoc
1   /**
2    *    Copyright 2006-2016 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.generator.internal;
17  
18  import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
19  import static org.mybatis.generator.internal.util.messages.Messages.getString;
20  
21  import java.net.URL;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.mybatis.generator.api.CommentGenerator;
26  import org.mybatis.generator.api.FullyQualifiedTable;
27  import org.mybatis.generator.api.JavaFormatter;
28  import org.mybatis.generator.api.Plugin;
29  import org.mybatis.generator.api.IntrospectedColumn;
30  import org.mybatis.generator.api.IntrospectedTable;
31  import org.mybatis.generator.api.JavaTypeResolver;
32  import org.mybatis.generator.api.XmlFormatter;
33  import org.mybatis.generator.api.dom.DefaultJavaFormatter;
34  import org.mybatis.generator.api.dom.DefaultXmlFormatter;
35  import org.mybatis.generator.codegen.ibatis2.IntrospectedTableIbatis2Java2Impl;
36  import org.mybatis.generator.codegen.ibatis2.IntrospectedTableIbatis2Java5Impl;
37  import org.mybatis.generator.codegen.mybatis3.IntrospectedTableMyBatis3Impl;
38  import org.mybatis.generator.codegen.mybatis3.IntrospectedTableMyBatis3SimpleImpl;
39  import org.mybatis.generator.config.CommentGeneratorConfiguration;
40  import org.mybatis.generator.config.Context;
41  import org.mybatis.generator.config.PluginConfiguration;
42  import org.mybatis.generator.config.JavaTypeResolverConfiguration;
43  import org.mybatis.generator.config.PropertyRegistry;
44  import org.mybatis.generator.config.TableConfiguration;
45  import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;
46  
47  /**
48   * This class creates the different objects needed by the generator.
49   *
50   * @author Jeff Butler
51   */
52  public class ObjectFactory {
53      
54      /** The external class loaders. */
55      private static List<ClassLoader> externalClassLoaders;
56      
57      /** The resource class loaders. */
58      private static List<ClassLoader> resourceClassLoaders;
59      
60      static {
61      	externalClassLoaders = new ArrayList<ClassLoader>();
62          resourceClassLoaders = new ArrayList<ClassLoader>();
63      }
64  
65      /**
66       * Utility class. No instances allowed
67       */
68      private ObjectFactory() {
69          super();
70      }
71  
72      /**
73       * Adds a custom classloader to the collection of classloaders searched for resources. Currently, this is only used
74       * when searching for properties files that may be referenced in the configuration file.
75       *
76       * @param classLoader
77       *            the class loader
78       */
79      public static synchronized void addResourceClassLoader(
80              ClassLoader classLoader) {
81          ObjectFactory.resourceClassLoaders.add(classLoader);
82      }
83  
84      /**
85       * Adds a custom classloader to the collection of classloaders searched for "external" classes. These are classes
86       * that do not depend on any of the generator's classes or interfaces. Examples are JDBC drivers, root classes, root
87       * interfaces, etc.
88       *
89       * @param classLoader
90       *            the class loader
91       */
92      public static synchronized void addExternalClassLoader(
93              ClassLoader classLoader) {
94          ObjectFactory.externalClassLoaders.add(classLoader);
95      }
96      
97      /**
98       * This method returns a class loaded from the context classloader, or the classloader supplied by a client. This is
99       * appropriate for JDBC drivers, model root classes, etc. It is not appropriate for any class that extends one of
100      * the supplied classes or interfaces.
101      *
102      * @param type
103      *            the type
104      * @return the Class loaded from the external classloader
105      * @throws ClassNotFoundException
106      *             the class not found exception
107      */
108     public static Class<?> externalClassForName(String type)
109             throws ClassNotFoundException {
110 
111         Class<?> clazz;
112 
113         for (ClassLoader classLoader : externalClassLoaders) {
114             try {
115                 clazz = Class.forName(type, true, classLoader);
116                 return clazz;
117             } catch (Throwable e) {
118                 // ignore - fail safe below
119             }
120         }
121         
122         return internalClassForName(type);
123     }
124 
125     /**
126      * Creates a new Object object.
127      *
128      * @param type
129      *            the type
130      * @return the object
131      */
132     public static Object createExternalObject(String type) {
133         Object answer;
134 
135         try {
136             Class<?> clazz = externalClassForName(type);
137             answer = clazz.newInstance();
138         } catch (Exception e) {
139             throw new RuntimeException(getString(
140                     "RuntimeError.6", type), e); //$NON-NLS-1$
141         }
142 
143         return answer;
144     }
145 
146     /**
147      * Internal class for name.
148      *
149      * @param type
150      *            the type
151      * @return the class
152      * @throws ClassNotFoundException
153      *             the class not found exception
154      */
155     public static Class<?> internalClassForName(String type)
156             throws ClassNotFoundException {
157         Class<?> clazz = null;
158 
159         try {
160             ClassLoader cl = Thread.currentThread().getContextClassLoader();
161             clazz = Class.forName(type, true, cl);
162         } catch (Exception e) {
163             // ignore - failsafe below
164         }
165 
166         if (clazz == null) {
167             clazz = Class.forName(type, true, ObjectFactory.class.getClassLoader());
168         }
169 
170         return clazz;
171     }
172 
173     /**
174      * Gets the resource.
175      *
176      * @param resource
177      *            the resource
178      * @return the resource
179      */
180     public static URL getResource(String resource) {
181         URL url;
182 
183         for (ClassLoader classLoader : resourceClassLoaders) {
184             url = classLoader.getResource(resource);
185             if (url != null) {
186               return url;
187             }
188         }
189         
190         ClassLoader cl = Thread.currentThread().getContextClassLoader();
191         url = cl.getResource(resource);
192 
193         if (url == null) {
194             url = ObjectFactory.class.getClassLoader().getResource(resource);
195         }
196 
197         return url;
198     }
199 
200     /**
201      * Creates a new Object object.
202      *
203      * @param type
204      *            the type
205      * @return the object
206      */
207     public static Object createInternalObject(String type) {
208         Object answer;
209 
210         try {
211             Class<?> clazz = internalClassForName(type);
212 
213             answer = clazz.newInstance();
214         } catch (Exception e) {
215             throw new RuntimeException(getString(
216                     "RuntimeError.6", type), e); //$NON-NLS-1$
217 
218         }
219 
220         return answer;
221     }
222 
223     /**
224      * Creates a new Object object.
225      *
226      * @param context
227      *            the context
228      * @param warnings
229      *            the warnings
230      * @return the java type resolver
231      */
232     public static JavaTypeResolver createJavaTypeResolver(Context context,
233             List<String> warnings) {
234         JavaTypeResolverConfiguration config = context
235                 .getJavaTypeResolverConfiguration();
236         String type;
237 
238         if (config != null && config.getConfigurationType() != null) {
239             type = config.getConfigurationType();
240             if ("DEFAULT".equalsIgnoreCase(type)) { //$NON-NLS-1$
241                 type = JavaTypeResolverDefaultImpl.class.getName();
242             }
243         } else {
244             type = JavaTypeResolverDefaultImpl.class.getName();
245         }
246 
247         JavaTypeResolver answer = (JavaTypeResolver) createInternalObject(type);
248         answer.setWarnings(warnings);
249 
250         if (config != null) {
251             answer.addConfigurationProperties(config.getProperties());
252         }
253 
254         answer.setContext(context);
255 
256         return answer;
257     }
258 
259     /**
260      * Creates a new Object object.
261      *
262      * @param context
263      *            the context
264      * @param pluginConfiguration
265      *            the plugin configuration
266      * @return the plugin
267      */
268     public static Plugin createPlugin(Context context,
269             PluginConfiguration pluginConfiguration) {
270         Plugin plugin = (Plugin) createInternalObject(pluginConfiguration
271                 .getConfigurationType());
272         plugin.setContext(context);
273         plugin.setProperties(pluginConfiguration.getProperties());
274         return plugin;
275     }
276 
277     /**
278      * Creates a new Object object.
279      *
280      * @param context
281      *            the context
282      * @return the comment generator
283      */
284     public static CommentGenerator createCommentGenerator(Context context) {
285 
286         CommentGeneratorConfiguration config = context
287                 .getCommentGeneratorConfiguration();
288         CommentGenerator answer;
289 
290         String type;
291         if (config == null || config.getConfigurationType() == null) {
292             type = DefaultCommentGenerator.class.getName();
293         } else {
294             type = config.getConfigurationType();
295         }
296 
297         answer = (CommentGenerator) createInternalObject(type);
298 
299         if (config != null) {
300             answer.addConfigurationProperties(config.getProperties());
301         }
302 
303         return answer;
304     }
305 
306     /**
307      * Creates a new Object object.
308      *
309      * @param context
310      *            the context
311      * @return the java formatter
312      */
313     public static JavaFormatter createJavaFormatter(Context context) {
314         String type = context.getProperty(PropertyRegistry.CONTEXT_JAVA_FORMATTER);
315         if (!stringHasValue(type)) {
316             type = DefaultJavaFormatter.class.getName();
317         }
318 
319         JavaFormatter answer = (JavaFormatter) createInternalObject(type);
320 
321         answer.setContext(context);
322 
323         return answer;
324     }
325     
326     /**
327      * Creates a new Object object.
328      *
329      * @param context
330      *            the context
331      * @return the xml formatter
332      */
333     public static XmlFormatter createXmlFormatter(Context context) {
334         String type = context.getProperty(PropertyRegistry.CONTEXT_XML_FORMATTER);
335         if (!stringHasValue(type)) {
336             type = DefaultXmlFormatter.class.getName();
337         }
338 
339         XmlFormatter answer = (XmlFormatter) createInternalObject(type);
340 
341         answer.setContext(context);
342 
343         return answer;
344     }
345     
346     /**
347      * Creates a new Object object.
348      *
349      * @param tableConfiguration
350      *            the table configuration
351      * @param table
352      *            the table
353      * @param context
354      *            the context
355      * @return the introspected table
356      */
357     public static IntrospectedTable createIntrospectedTable(
358             TableConfiguration tableConfiguration, FullyQualifiedTable table,
359             Context context) {
360 
361         IntrospectedTable answer = createIntrospectedTableForValidation(context);
362         answer.setFullyQualifiedTable(table);
363         answer.setTableConfiguration(tableConfiguration);
364 
365         return answer;
366     }
367 
368     /**
369      * This method creates an introspected table implementation that is only usable for validation (i.e. for a context
370      * to determine if the target is ibatis2 or mybatis3).
371      * 
372      *
373      * @param context
374      *            the context
375      * @return the introspected table
376      */
377     public static IntrospectedTable createIntrospectedTableForValidation(Context context) {
378         String type = context.getTargetRuntime();
379         if (!stringHasValue(type)) {
380             type = IntrospectedTableMyBatis3Impl.class.getName();
381         } else if ("Ibatis2Java2".equalsIgnoreCase(type)) { //$NON-NLS-1$
382             type = IntrospectedTableIbatis2Java2Impl.class.getName();
383         } else if ("Ibatis2Java5".equalsIgnoreCase(type)) { //$NON-NLS-1$
384             type = IntrospectedTableIbatis2Java5Impl.class.getName();
385         } else if ("Ibatis3".equalsIgnoreCase(type)) { //$NON-NLS-1$
386             type = IntrospectedTableMyBatis3Impl.class.getName();
387         } else if ("MyBatis3".equalsIgnoreCase(type)) { //$NON-NLS-1$
388             type = IntrospectedTableMyBatis3Impl.class.getName();
389         } else if ("MyBatis3Simple".equalsIgnoreCase(type)) { //$NON-NLS-1$
390             type = IntrospectedTableMyBatis3SimpleImpl.class.getName();
391         }
392 
393         IntrospectedTable answer = (IntrospectedTable) createInternalObject(type);
394         answer.setContext(context);
395 
396         return answer;
397     }
398     
399     /**
400      * Creates a new Object object.
401      *
402      * @param context
403      *            the context
404      * @return the introspected column
405      */
406     public static IntrospectedColumn createIntrospectedColumn(Context context) {
407         String type = context.getIntrospectedColumnImpl();
408         if (!stringHasValue(type)) {
409             type = IntrospectedColumn.class.getName();
410         }
411 
412         IntrospectedColumn answer = (IntrospectedColumn) createInternalObject(type);
413         answer.setContext(context);
414 
415         return answer;
416     }
417 }