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