1 /*
2  * Copyright (C) 2013 Brett Wooldridge
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
17 package com.zaxxer.hikari.util;
18
19 import java.lang.reflect.Constructor;
20 import java.util.Locale;
21 import java.util.concurrent.*;
22
23 import static java.lang.Thread.currentThread;
24 import static java.util.concurrent.TimeUnit.SECONDS;
25
26 /**
27  *
28  * @author Brett Wooldridge
29  */

30 public final class UtilityElf
31 {
32    /**
33     *
34     * @return null if string is null or empty
35    */

36    public static String getNullIfEmpty(final String text)
37    {
38       return text == null ? null : text.trim().isEmpty() ? null : text.trim();
39    }
40
41    /**
42     * Sleep and suppress InterruptedException (but re-signal it).
43     *
44     * @param millis the number of milliseconds to sleep
45     */

46    public static void quietlySleep(final long millis)
47    {
48       try {
49          Thread.sleep(millis);
50       }
51       catch (InterruptedException e) {
52          // I said be quiet!
53          currentThread().interrupt();
54       }
55    }
56
57    /**
58     * Checks whether an object is an instance of given type without throwing exception when the class is not loaded.
59     * @param obj the object to check
60     * @param className String class
61     * @return true if object is assignable from the type, false otherwise or when the class cannot be loaded
62     */

63    public static boolean safeIsAssignableFrom(Object obj, String className) {
64       try {
65          Class<?> clazz = Class.forName(className);
66          return clazz.isAssignableFrom(obj.getClass());
67       } catch (ClassNotFoundException ignored) {
68          return false;
69       }
70    }
71
72    /**
73     * Create and instance of the specified class using the constructor matching the specified
74     * arguments.
75     *
76     * @param <T> the class type
77     * @param className the name of the class to instantiate
78     * @param clazz a class to cast the result as
79     * @param args arguments to a constructor
80     * @return an instance of the specified class
81     */

82    public static <T> T createInstance(final String className, final Class<T> clazz, final Object... args)
83    {
84       if (className == null) {
85          return null;
86       }
87
88       try {
89          Class<?> loaded = UtilityElf.class.getClassLoader().loadClass(className);
90          if (args.length == 0) {
91             return clazz.cast(loaded.newInstance());
92          }
93
94          Class<?>[] argClasses = new Class<?>[args.length];
95          for (int i = 0; i < args.length; i++) {
96             argClasses[i] = args[i].getClass();
97          }
98          Constructor<?> constructor = loaded.getConstructor(argClasses);
99          return clazz.cast(constructor.newInstance(args));
100       }
101       catch (Exception e) {
102          throw new RuntimeException(e);
103       }
104    }
105
106    /**
107     * Create a ThreadPoolExecutor.
108     *
109     * @param queueSize the queue size
110     * @param threadName the thread name
111     * @param threadFactory an optional ThreadFactory
112     * @param policy the RejectedExecutionHandler policy
113     * @return a ThreadPoolExecutor
114     */

115    public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName, ThreadFactory threadFactory, final RejectedExecutionHandler policy)
116    {
117       if (threadFactory == null) {
118          threadFactory = new DefaultThreadFactory(threadName, true);
119       }
120
121       LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(queueSize);
122       ThreadPoolExecutor executor = new ThreadPoolExecutor(1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, queue, threadFactory, policy);
123       executor.allowCoreThreadTimeOut(true);
124       return executor;
125    }
126
127    /**
128     * Create a ThreadPoolExecutor.
129     *
130     * @param queue the BlockingQueue to use
131     * @param threadName the thread name
132     * @param threadFactory an optional ThreadFactory
133     * @param policy the RejectedExecutionHandler policy
134     * @return a ThreadPoolExecutor
135     */

136    public static ThreadPoolExecutor createThreadPoolExecutor(final BlockingQueue<Runnable> queue, final String threadName, ThreadFactory threadFactory, final RejectedExecutionHandler policy)
137    {
138       if (threadFactory == null) {
139          threadFactory = new DefaultThreadFactory(threadName, true);
140       }
141
142       ThreadPoolExecutor executor = new ThreadPoolExecutor(1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, queue, threadFactory, policy);
143       executor.allowCoreThreadTimeOut(true);
144       return executor;
145    }
146
147    // ***********************************************************************
148    //                       Misc. public methods
149    // ***********************************************************************
150
151    /**
152     * Get the int value of a transaction isolation level by name.
153     *
154     * @param transactionIsolationName the name of the transaction isolation level
155     * @return the int value of the isolation level or -1
156     */

157    public static int getTransactionIsolation(final String transactionIsolationName)
158    {
159       if (transactionIsolationName != null) {
160          try {
161             // use the english locale to avoid the infamous turkish locale bug
162             final String upperCaseIsolationLevelName = transactionIsolationName.toUpperCase(Locale.ENGLISH);
163             return IsolationLevel.valueOf(upperCaseIsolationLevelName).getLevelId();
164          } catch (IllegalArgumentException e) {
165             // legacy support for passing an integer version of the isolation level
166             try {
167                final int level = Integer.parseInt(transactionIsolationName);
168                for (IsolationLevel iso : IsolationLevel.values()) {
169                   if (iso.getLevelId() == level) {
170                      return iso.getLevelId();
171                   }
172                }
173
174                throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
175             }
176             catch (NumberFormatException nfe) {
177                throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName, nfe);
178             }
179          }
180       }
181
182       return -1;
183    }
184
185    public static final class DefaultThreadFactory implements ThreadFactory {
186
187       private final String threadName;
188       private final boolean daemon;
189
190       public DefaultThreadFactory(String threadName, boolean daemon) {
191          this.threadName = threadName;
192          this.daemon = daemon;
193       }
194
195       @Override
196       public Thread newThread(Runnable r) {
197          Thread thread = new Thread(r, threadName);
198          thread.setDaemon(daemon);
199          return thread;
200       }
201    }
202 }
203