PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/components/camel-guice/src/main/java/org/apache/camel/guice/inject/Injectors.java

https://gitlab.com/matticala/apache-camel
Java | 457 lines | 286 code | 34 blank | 137 comment | 58 complexity | 532608309008005bbc59c594aa1d1c5e MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.camel.guice.inject;
  18. import java.lang.annotation.Annotation;
  19. import java.lang.reflect.Field;
  20. import java.lang.reflect.Type;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Map.Entry;
  24. import java.util.Set;
  25. import java.util.StringTokenizer;
  26. import com.google.common.collect.Lists;
  27. import com.google.common.collect.Sets;
  28. import com.google.inject.AbstractModule;
  29. import com.google.inject.Binding;
  30. import com.google.inject.Guice;
  31. import com.google.inject.Injector;
  32. import com.google.inject.Key;
  33. import com.google.inject.Module;
  34. import com.google.inject.Provider;
  35. import com.google.inject.Scope;
  36. import com.google.inject.Singleton;
  37. import com.google.inject.TypeLiteral;
  38. import com.google.inject.internal.BindingImpl;
  39. import com.google.inject.internal.Scoping;
  40. import com.google.inject.matcher.Matcher;
  41. import com.google.inject.name.Names;
  42. import com.google.inject.util.Modules;
  43. import org.apache.camel.guice.jndi.GuiceInitialContextFactory;
  44. import org.apache.camel.guice.jndi.internal.Classes;
  45. import org.apache.camel.guice.support.CloseErrors;
  46. import org.apache.camel.guice.support.CloseFailedException;
  47. import org.apache.camel.guice.support.Closer;
  48. import org.apache.camel.guice.support.Closers;
  49. import org.apache.camel.guice.support.CompositeCloser;
  50. import org.apache.camel.guice.support.HasScopeAnnotation;
  51. import org.apache.camel.guice.support.internal.CloseErrorsImpl;
  52. @SuppressWarnings({ "rawtypes", "unchecked" })
  53. public final class Injectors {
  54. public static final String MODULE_CLASS_NAMES = "org.guiceyfruit.modules";
  55. private Injectors() {
  56. //Helper class
  57. }
  58. /**
  59. * Creates an injector from the given properties, loading any modules define
  60. * by the {@link #MODULE_CLASS_NAMES} property value (space separated) along
  61. * with any other modules passed as an argument.
  62. *
  63. * @param environment
  64. * the properties used to create the injector
  65. * @param overridingModules
  66. * any modules which override the modules referenced in the
  67. * environment such as to provide the actual JNDI context
  68. */
  69. public static Injector createInjector(final Map environment,
  70. Module... overridingModules) throws ClassNotFoundException,
  71. IllegalAccessException, InstantiationException {
  72. List<Module> modules = Lists.newArrayList();
  73. // lets bind the properties
  74. modules.add(new AbstractModule() {
  75. protected void configure() {
  76. Names.bindProperties(binder(), environment);
  77. }
  78. });
  79. Object moduleValue = environment.get(MODULE_CLASS_NAMES);
  80. if (moduleValue instanceof String) {
  81. String names = (String) moduleValue;
  82. StringTokenizer iter = new StringTokenizer(names);
  83. while (iter.hasMoreTokens()) {
  84. String moduleName = iter.nextToken();
  85. Module module = loadModule(moduleName);
  86. if (module != null) {
  87. modules.add(module);
  88. }
  89. }
  90. }
  91. Injector injector = Guice.createInjector(Modules.override(modules)
  92. .with(overridingModules));
  93. return injector;
  94. }
  95. /**
  96. * Returns an instance of the given type with the
  97. * {@link com.google.inject.name.Named} annotation value.
  98. *
  99. * This method allows you to switch this code
  100. * <code>injector.getInstance(Key.get(type, Names.named(name)));</code>
  101. *
  102. * to the more concise
  103. * <code>Injectors.getInstance(injector, type, name);</code>
  104. */
  105. public static <T> T getInstance(Injector injector, java.lang.Class<T> type,
  106. String name) {
  107. return injector.getInstance(Key.get(type, Names.named(name)));
  108. }
  109. /**
  110. * Returns a collection of all instances of the given base type
  111. *
  112. * @param baseClass
  113. * the base type of objects required
  114. * @param <T>
  115. * the base type
  116. * @return a set of objects returned from this injector
  117. */
  118. public static <T> Set<T> getInstancesOf(Injector injector,
  119. Class<T> baseClass) {
  120. Set<T> answer = Sets.newHashSet();
  121. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  122. .entrySet();
  123. for (Entry<Key<?>, Binding<?>> entry : entries) {
  124. Key<?> key = entry.getKey();
  125. Class<?> keyType = getKeyType(key);
  126. if (keyType != null && baseClass.isAssignableFrom(keyType)) {
  127. Binding<?> binding = entry.getValue();
  128. Object value = binding.getProvider().get();
  129. if (value != null) {
  130. T castValue = baseClass.cast(value);
  131. answer.add(castValue);
  132. }
  133. }
  134. }
  135. return answer;
  136. }
  137. /**
  138. * Returns a collection of all instances matching the given matcher
  139. *
  140. * @param matcher
  141. * matches the types to return instances
  142. * @return a set of objects returned from this injector
  143. */
  144. public static <T> Set<T> getInstancesOf(Injector injector,
  145. Matcher<Class> matcher) {
  146. Set<T> answer = Sets.newHashSet();
  147. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  148. .entrySet();
  149. for (Entry<Key<?>, Binding<?>> entry : entries) {
  150. Key<?> key = entry.getKey();
  151. Class<?> keyType = getKeyType(key);
  152. if (keyType != null && matcher.matches(keyType)) {
  153. Binding<?> binding = entry.getValue();
  154. Object value = binding.getProvider().get();
  155. answer.add((T) value);
  156. }
  157. }
  158. return answer;
  159. }
  160. /**
  161. * Returns a collection of all of the providers matching the given matcher
  162. *
  163. * @param matcher
  164. * matches the types to return instances
  165. * @return a set of objects returned from this injector
  166. */
  167. public static <T> Set<Provider<T>> getProvidersOf(Injector injector,
  168. Matcher<Class> matcher) {
  169. Set<Provider<T>> answer = Sets.newHashSet();
  170. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  171. .entrySet();
  172. for (Entry<Key<?>, Binding<?>> entry : entries) {
  173. Key<?> key = entry.getKey();
  174. Class<?> keyType = getKeyType(key);
  175. if (keyType != null && matcher.matches(keyType)) {
  176. Binding<?> binding = entry.getValue();
  177. answer.add((Provider<T>) binding.getProvider());
  178. }
  179. }
  180. return answer;
  181. }
  182. /**
  183. * Returns a collection of all providers of the given base type
  184. *
  185. * @param baseClass
  186. * the base type of objects required
  187. * @param <T>
  188. * the base type
  189. * @return a set of objects returned from this injector
  190. */
  191. public static <T> Set<Provider<T>> getProvidersOf(Injector injector,
  192. Class<T> baseClass) {
  193. Set<Provider<T>> answer = Sets.newHashSet();
  194. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  195. .entrySet();
  196. for (Entry<Key<?>, Binding<?>> entry : entries) {
  197. Key<?> key = entry.getKey();
  198. Class<?> keyType = getKeyType(key);
  199. if (keyType != null && baseClass.isAssignableFrom(keyType)) {
  200. Binding<?> binding = entry.getValue();
  201. answer.add((Provider<T>) binding.getProvider());
  202. }
  203. }
  204. return answer;
  205. }
  206. /** Returns true if a binding exists for the given matcher */
  207. public static boolean hasBinding(Injector injector, Matcher<Class> matcher) {
  208. return !getBindingsOf(injector, matcher).isEmpty();
  209. }
  210. /** Returns true if a binding exists for the given base class */
  211. public static boolean hasBinding(Injector injector, Class<?> baseClass) {
  212. return !getBindingsOf(injector, baseClass).isEmpty();
  213. }
  214. /** Returns true if a binding exists for the given key */
  215. public static boolean hasBinding(Injector injector, Key<?> key) {
  216. Binding<?> binding = getBinding(injector, key);
  217. return binding != null;
  218. }
  219. /**
  220. * Returns the binding for the given key or null if there is no such binding
  221. */
  222. public static Binding<?> getBinding(Injector injector, Key<?> key) {
  223. Map<Key<?>, Binding<?>> bindings = injector.getBindings();
  224. Binding<?> binding = bindings.get(key);
  225. return binding;
  226. }
  227. /**
  228. * Returns a collection of all of the bindings matching the given matcher
  229. *
  230. * @param matcher
  231. * matches the types to return instances
  232. * @return a set of objects returned from this injector
  233. */
  234. public static Set<Binding<?>> getBindingsOf(Injector injector,
  235. Matcher<Class> matcher) {
  236. Set<Binding<?>> answer = Sets.newHashSet();
  237. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  238. .entrySet();
  239. for (Entry<Key<?>, Binding<?>> entry : entries) {
  240. Key<?> key = entry.getKey();
  241. Class<?> keyType = getKeyType(key);
  242. if (keyType != null && matcher.matches(keyType)) {
  243. answer.add(entry.getValue());
  244. }
  245. }
  246. return answer;
  247. }
  248. /**
  249. * Returns a collection of all bindings of the given base type
  250. *
  251. * @param baseClass
  252. * the base type of objects required
  253. * @return a set of objects returned from this injector
  254. */
  255. public static Set<Binding<?>> getBindingsOf(Injector injector,
  256. Class<?> baseClass) {
  257. Set<Binding<?>> answer = Sets.newHashSet();
  258. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  259. .entrySet();
  260. for (Entry<Key<?>, Binding<?>> entry : entries) {
  261. Key<?> key = entry.getKey();
  262. Class<?> keyType = getKeyType(key);
  263. if (keyType != null && baseClass.isAssignableFrom(keyType)) {
  264. answer.add(entry.getValue());
  265. }
  266. }
  267. return answer;
  268. }
  269. /** Returns the key type of the given key */
  270. public static <T> Class<?> getKeyType(Key<?> key) {
  271. Class<?> keyType = null;
  272. TypeLiteral<?> typeLiteral = key.getTypeLiteral();
  273. Type type = typeLiteral.getType();
  274. if (type instanceof Class) {
  275. keyType = (Class<?>) type;
  276. }
  277. return keyType;
  278. }
  279. protected static Module loadModule(String moduleName)
  280. throws ClassNotFoundException, IllegalAccessException,
  281. InstantiationException {
  282. Class<?> type = Classes.loadClass(moduleName,
  283. GuiceInitialContextFactory.class.getClassLoader());
  284. return (Module) type.newInstance();
  285. }
  286. /*
  287. */
  288. /**
  289. * Closes the given scope on this injector
  290. *
  291. * @param injector
  292. * the injector on which to close objects
  293. * @param scopeAnnotation
  294. * the scope on which to close the objects
  295. * @throws CloseFailedException
  296. * the exceptions caused if closing an object fails
  297. */
  298. /*
  299. * public static void close(Injector injector, Annotation scopeAnnotation)
  300. * throws CloseFailedException { Key<PreDestroyer> key =
  301. * Key.get(PreDestroyer.class, scopeAnnotation); if (hasBinding(injector,
  302. * key)) { PreDestroyer destroyer = injector.getInstance(key);
  303. * destroyer.close(); } }
  304. */
  305. /**
  306. * Closes any singleton objects in the injector using the currently
  307. * registered {@link Closer} implementations
  308. */
  309. public static void close(Injector injector) throws CloseFailedException {
  310. close(injector, new CloseErrorsImpl(Injectors.class));
  311. }
  312. /**
  313. * Closes objects within the given scope using the currently registered
  314. * {@link Closer} implementations
  315. */
  316. public static void close(Injector injector, CloseErrors errors)
  317. throws CloseFailedException {
  318. close(injector, Singleton.class, errors);
  319. }
  320. /**
  321. * Closes objects within the given scope using the currently registered
  322. * {@link Closer} implementations
  323. */
  324. public static void close(Injector injector,
  325. Class<? extends Annotation> scopeAnnotationToClose)
  326. throws CloseFailedException {
  327. close(injector, scopeAnnotationToClose, new CloseErrorsImpl(
  328. Injectors.class));
  329. }
  330. /**
  331. * Closes objects within the given scope using the currently registered
  332. * {@link Closer} implementations
  333. */
  334. public static void close(Injector injector,
  335. Class<? extends Annotation> scopeAnnotationToClose,
  336. CloseErrors errors) throws CloseFailedException {
  337. Set<Closer> closers = getInstancesOf(injector, Closer.class);
  338. Closer closer = CompositeCloser.newInstance(closers);
  339. if (closer == null) {
  340. return;
  341. }
  342. Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings()
  343. .entrySet();
  344. for (Entry<Key<?>, Binding<?>> entry : entries) {
  345. Key<?> key = entry.getKey();
  346. Binding<?> binding = entry.getValue();
  347. closeBinding(key, binding, scopeAnnotationToClose, closer, errors);
  348. }
  349. tryCloseJitBindings(closer, injector, scopeAnnotationToClose, errors);
  350. errors.throwIfNecessary();
  351. }
  352. private static void tryCloseJitBindings(Closer closer, Injector injector,
  353. Class<? extends Annotation> scopeAnnotationToClose,
  354. CloseErrors errors) {
  355. Class<? extends Injector> type = injector.getClass();
  356. Field field;
  357. try {
  358. field = type.getDeclaredField("jitBindings");
  359. field.setAccessible(true);
  360. Object bindings = field.get(injector);
  361. if (bindings != null) {
  362. if (bindings instanceof Map) {
  363. Map<Key<?>, BindingImpl<?>> map = (Map<Key<?>, BindingImpl<?>>) bindings;
  364. Set<Entry<Key<?>, BindingImpl<?>>> entries = map.entrySet();
  365. for (Entry<Key<?>, BindingImpl<?>> entry : entries) {
  366. closeBinding(entry.getKey(), entry.getValue(),
  367. scopeAnnotationToClose, closer, errors);
  368. }
  369. }
  370. }
  371. } catch (NoSuchFieldException e) {
  372. // ignore - Guice has refactored so we can't access the jit bindings
  373. // System.out.println("No such field! " + e);
  374. } catch (IllegalAccessException e) {
  375. // ignore - Guice has refactored so we can't access the jit bindings
  376. // System.out.println("Failed to access field: " + field +
  377. // ". Reason: " + e);
  378. }
  379. }
  380. private static void closeBinding(Key<?> key, Binding<?> binding,
  381. Class<? extends Annotation> scopeAnnotationToClose, Closer closer,
  382. CloseErrors errors) {
  383. Provider<?> provider = binding.getProvider();
  384. Class<? extends Annotation> scopeAnnotation = getScopeAnnotation(binding);
  385. if ((scopeAnnotation != null)
  386. && scopeAnnotation.equals(scopeAnnotationToClose)) {
  387. Object value = provider.get();
  388. if (value != null) {
  389. Closers.close(key, value, closer, errors);
  390. }
  391. }
  392. }
  393. /**
  394. * Returns the scope annotation for the given binding or null if there is no
  395. * scope
  396. */
  397. public static Class<? extends Annotation> getScopeAnnotation(
  398. Binding<?> binding) {
  399. Class<? extends Annotation> scopeAnnotation = null;
  400. if (binding instanceof BindingImpl) {
  401. BindingImpl bindingImpl = (BindingImpl) binding;
  402. Scoping scoping = bindingImpl.getScoping();
  403. if (scoping != null) {
  404. scopeAnnotation = scoping.getScopeAnnotation();
  405. // TODO not sure why we need this hack???
  406. if (scopeAnnotation == null) {
  407. Scope scope = scoping.getScopeInstance();
  408. if (scope instanceof HasScopeAnnotation) {
  409. HasScopeAnnotation hasScopeAnnotation = (HasScopeAnnotation) scope;
  410. scopeAnnotation = hasScopeAnnotation
  411. .getScopeAnnotation();
  412. }
  413. if (scopeAnnotation == null
  414. && (scoping == Scoping.EAGER_SINGLETON
  415. || scoping == Scoping.SINGLETON_ANNOTATION || scoping == Scoping.SINGLETON_INSTANCE)) {
  416. scopeAnnotation = Singleton.class;
  417. }
  418. }
  419. }
  420. }
  421. return scopeAnnotation;
  422. }
  423. }