1 package com.vladmihalcea.hibernate.type.util;
2
3 import com.fasterxml.jackson.databind.ObjectMapper;
4 import org.hibernate.cfg.Environment;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import java.io.File;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.net.MalformedURLException;
12 import java.net.URL;
13 import java.util.Properties;
14 import java.util.function.Supplier;
15
16 /**
17  * <code>Configuration</code> - It allows declarative configuration through the <code>hibernate.properties</code> file
18  * or the <code>hibernate-types.properties</code> file.
19  *
20  * The properties from <code>hibernate-types.properties</code> can override the ones from the <code>hibernate.properties</code> file.
21  *
22  * It loads the {@link Properties} configuration file and makes them available to other components.
23  *
24  * @author Vlad Mihalcea
25  * @since 2.1.0
26  */

27 public class Configuration {
28
29     private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
30
31     public static final Configuration INSTANCE = new Configuration();
32
33     public static final String PROPERTIES_FILE_PATH = "hibernate-types.properties.path";
34     public static final String PROPERTIES_FILE_NAME = "hibernate-types.properties";
35
36     /**
37      * Each Property has a well-defined key.
38      */

39     public enum PropertyKey {
40         JACKSON_OBJECT_MAPPER("hibernate.types.jackson.object.mapper"),
41         JSON_SERIALIZER("hibernate.types.json.serializer"),
42         PRINT_BANNER("hibernate.types.print.banner");
43
44         private final String key;
45
46         PropertyKey(String key) {
47             this.key = key;
48         }
49
50         public String getKey() {
51             return key;
52         }
53     }
54
55     private final Properties properties = Environment.getProperties();
56
57     public Configuration() {
58         load();
59
60         if(ReflectionUtils.getClassOrNull("io.hypersistence.optimizer.HypersistenceOptimizer") == null) {
61             printBanner();
62         }
63     }
64
65     /**
66      * Load {@link Properties} from the resolved {@link InputStream}
67      */

68     private void load() {
69         InputStream propertiesInputStream = null;
70         try {
71             propertiesInputStream = propertiesInputStream();
72             if (propertiesInputStream != null) {
73                 properties.load(propertiesInputStream);
74             }
75         } catch (IOException e) {
76             LOGGER.error("Can't load properties", e);
77         } finally {
78             try {
79                 if (propertiesInputStream != null) {
80                     propertiesInputStream.close();
81                 }
82             } catch (IOException e) {
83                 LOGGER.error("Can't close the properties InputStream", e);
84             }
85         }
86     }
87
88     /**
89      * Get {@link Properties} file {@link InputStream}
90      *
91      * @return {@link Properties} file {@link InputStream}
92      * @throws IOException the file couldn't be loaded properly
93      */

94     private InputStream propertiesInputStream() throws IOException {
95         String propertiesFilePath = System.getProperty(PROPERTIES_FILE_PATH);
96         URL propertiesFileUrl = null;
97         if (propertiesFilePath != null) {
98             try {
99                 propertiesFileUrl = new URL(propertiesFilePath);
100             } catch (MalformedURLException ignore) {
101                 propertiesFileUrl = ClassLoaderUtils.getResource(propertiesFilePath);
102                 if (propertiesFileUrl == null) {
103                     File f = new File(propertiesFilePath);
104                     if (f.exists() && f.isFile()) {
105                         try {
106                             propertiesFileUrl = f.toURI().toURL();
107                         } catch (MalformedURLException e) {
108                             LOGGER.error(
109                                 "The property " + propertiesFilePath + " can't be resolved to either a URL, " +
110                                 "a classpath resource or a File"
111                             );
112                         }
113                     }
114                 }
115             }
116             if (propertiesFileUrl != null) {
117                 return propertiesFileUrl.openStream();
118             }
119         }
120         return ClassLoaderUtils.getResourceAsStream(PROPERTIES_FILE_NAME);
121     }
122
123     /**
124      * Get all properties.
125      *
126      * @return properties.
127      */

128     public Properties getProperties() {
129         return properties;
130     }
131
132     /**
133      * Get {@link ObjectMapperWrapper} reference
134      *
135      * @return {@link ObjectMapperWrapper} reference
136      */

137     public ObjectMapperWrapper getObjectMapperWrapper() {
138         Object objectMapperPropertyInstance = instantiateClass(PropertyKey.JACKSON_OBJECT_MAPPER);
139
140         ObjectMapperWrapper objectMapperWrapper = new ObjectMapperWrapper();
141
142         if (objectMapperPropertyInstance != null) {
143             if(objectMapperPropertyInstance instanceof ObjectMapperSupplier) {
144                 ObjectMapper objectMapper = ((ObjectMapperSupplier) objectMapperPropertyInstance).get();
145                 if(objectMapper != null) {
146                     objectMapperWrapper = new ObjectMapperWrapper(objectMapper);
147                 }
148             }
149             else if (objectMapperPropertyInstance instanceof Supplier) {
150                 Supplier<ObjectMapper> objectMapperSupplier = (Supplier<ObjectMapper>) objectMapperPropertyInstance;
151                 objectMapperWrapper = new ObjectMapperWrapper(objectMapperSupplier.get());
152             }
153             else if (objectMapperPropertyInstance instanceof ObjectMapper) {
154                 ObjectMapper objectMapper = (ObjectMapper) objectMapperPropertyInstance;
155                 objectMapperWrapper = new ObjectMapperWrapper(objectMapper);
156             }
157         }
158
159         Object jsonSerializerPropertyInstance = instantiateClass(PropertyKey.JSON_SERIALIZER);
160
161         if (jsonSerializerPropertyInstance != null) {
162             JsonSerializer jsonSerializer = null;
163
164             if(jsonSerializerPropertyInstance instanceof JsonSerializerSupplier) {
165                 jsonSerializer = ((JsonSerializerSupplier) jsonSerializerPropertyInstance).get();
166             }
167             else if (jsonSerializerPropertyInstance instanceof Supplier) {
168                 Supplier<JsonSerializer> jsonSerializerSupplier = (Supplier<JsonSerializer>) jsonSerializerPropertyInstance;
169                 jsonSerializer = jsonSerializerSupplier.get();
170             }
171             else if (jsonSerializerPropertyInstance instanceof JsonSerializer) {
172                 jsonSerializer = (JsonSerializer) jsonSerializerPropertyInstance;
173             }
174
175             if (jsonSerializer != null) {
176                 objectMapperWrapper.setJsonSerializer(jsonSerializer);
177             }
178         }
179
180         return objectMapperWrapper;
181     }
182
183     /**
184      * Get Integer property value
185      *
186      * @param propertyKey property key
187      * @return Integer property value
188      */

189     public Integer integerProperty(PropertyKey propertyKey) {
190         Integer value = null;
191         String property = properties.getProperty(propertyKey.getKey());
192         if (property != null) {
193             value = Integer.valueOf(property);
194         }
195         return value;
196     }
197
198     /**
199      * Get Long property value
200      *
201      * @param propertyKey property key
202      * @return Long property value
203      */

204     public Long longProperty(PropertyKey propertyKey) {
205         Long value = null;
206         String property = properties.getProperty(propertyKey.getKey());
207         if (property != null) {
208             value = Long.valueOf(property);
209         }
210         return value;
211     }
212
213     /**
214      * Get Boolean property value
215      *
216      * @param propertyKey property key
217      * @return Boolean property value
218      */

219     public Boolean booleanProperty(PropertyKey propertyKey) {
220         Boolean value = null;
221         String property = properties.getProperty(propertyKey.getKey());
222         if (property != null) {
223             value = Boolean.valueOf(property);
224         }
225         return value;
226     }
227
228     /**
229      * Get Class property value
230      *
231      * @param propertyKey property key
232      * @param <T> class generic type
233      * @return Class property value
234      */

235     public <T> Class<T> classProperty(PropertyKey propertyKey) {
236         Class<T> clazz = null;
237         String property = properties.getProperty(propertyKey.getKey());
238         if (property != null) {
239             try {
240                 return ClassLoaderUtils.loadClass(property);
241             } catch (ClassNotFoundException e) {
242                 LOGGER.error("Couldn't load the " + property + class given by the " + propertyKey + " property", e);
243             }
244         }
245         return clazz;
246     }
247
248     /**
249      * Instantiate class associated to the given property key
250      *
251      * @param propertyKey property key
252      * @param <T>         class parameter type
253      * @return class instance
254      */

255     private <T> T instantiateClass(PropertyKey propertyKey) {
256         T object = null;
257         String property = properties.getProperty(propertyKey.getKey());
258         if (property != null) {
259             try {
260                 Class<T> clazz = ClassLoaderUtils.loadClass(property);
261                 LOGGER.debug("Instantiate {}", clazz);
262                 object = clazz.newInstance();
263             } catch (ClassNotFoundException e) {
264                 LOGGER.error("Couldn't load the " + property + class given by the " + propertyKey + " property", e);
265             } catch (InstantiationException e) {
266                 LOGGER.error("Couldn't instantiate the " + property + class given by the " + propertyKey + " property", e);
267             } catch (IllegalAccessException e) {
268                 LOGGER.error("Couldn't access the " + property + class given by the " + propertyKey + " property", e);
269             }
270         }
271         return object;
272     }
273
274     /**
275      * Print the banner into the log.
276      */

277     private void printBanner() {
278         String printBannerValue = properties.getProperty(PropertyKey.PRINT_BANNER.getKey());
279         if(printBannerValue != null && !Boolean.valueOf(printBannerValue)) {
280             return;
281         }
282
283         Logger logger = LoggerFactory.getLogger("Hypersistence Optimizer");
284
285         printWarning("You should use Hypersistence Optimizer to speed up your Hibernate application!", logger);
286         printWarning("For more details, go to https://vladmihalcea.com/hypersistence-optimizer/", logger);
287
288
289         printInfo(
290             StringUtils.join(
291                 StringUtils.LINE_SEPARATOR,
292                 "",
293                 " _    _                           _     _",
294                 "| |  | |                         (_)   | |",
295                 "| |__| |_   _ _ __   ___ _ __ ___ _ ___| |_ ___ _ __   ___ ___",
296                 "|  __  | | | | '_ \\ / _ \\ '__/ __| / __| __/ _ \\ '_ \\ / __/ _ \\",
297                 "| |  | | |_| | |_) |  __/ |  \\__ \\ \\__ \\ ||  __/ | | | (_|  __/",
298                 "|_|  |_|\\__, | .__/ \\___|_|  |___/_|___/\\__\\___|_| |_|\\___\\___|",
299                 "         __/ | |",
300                 "        |___/|_|",
301                 "",
302                 "           ____        _   _           _",
303                 "          / __ \\      | | (_)         (_)",
304                 "         | |  | |_ __ | |_ _ _ __ ___  _ _______ _ __",
305                 "         | |  | | '_ \\| __| | '_ ` _ \\| |_  / _ \\ '__|",
306                 "         | |__| | |_) | |_| | | | | | | |/ /  __/ |",
307                 "          \\____/| .__/ \\__|_|_| |_| |_|_/___\\___|_|",
308                 "                | |",
309                 "                |_|",
310                 ""
311             ),
312             logger
313         );
314     }
315
316     private void printWarning(String message, Logger logger) {
317         if (logger.isWarnEnabled()) {
318             logger.warn(message);
319         } else {
320             System.out.println(message);
321         }
322     }
323
324     private void printInfo(String message, Logger logger) {
325         if (logger.isInfoEnabled()) {
326             logger.info(message);
327         } else {
328             System.out.println(message);
329         }
330     }
331 }
332