Merge "Add Mycilla code to odlguice"
[odlguice.git] / inject / inject-guice-extensions / jsr250 / src / main / java / org / opendaylight / odlguice / inject / guice / extensions / jsr250 / Jsr250Module.java
diff --git a/inject/inject-guice-extensions/jsr250/src/main/java/org/opendaylight/odlguice/inject/guice/extensions/jsr250/Jsr250Module.java b/inject/inject-guice-extensions/jsr250/src/main/java/org/opendaylight/odlguice/inject/guice/extensions/jsr250/Jsr250Module.java
new file mode 100755 (executable)
index 0000000..dd19320
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 Mycila (mathieu.carbou@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.odlguice.inject.guice.extensions.jsr250;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.inject.AbstractModule;
+import com.google.inject.Binding;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Scope;
+import com.google.inject.Scopes;
+import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.ProviderInstanceBinding;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+import org.gaul.modernizer_maven_annotations.SuppressModernizer;
+import org.opendaylight.odlguice.inject.guice.extensions.closeable.CloseableInjector;
+import org.opendaylight.odlguice.inject.guice.extensions.closeable.InjectorCloseListener;
+import org.opendaylight.odlguice.inject.guice.extensions.injection.MBinder;
+import org.opendaylight.odlguice.inject.guice.extensions.injection.MethodHandler;
+import org.opendaylight.odlguice.inject.guice.extensions.injection.Reflect;
+
+/**
+ * This code originated in https://github.com/mycila/guice and was forked into
+ * OpenDaylight.
+ * @author Mathieu Carbou (mathieu.carbou@gmail.com)
+ */
+@SuppressModernizer
+public class Jsr250Module extends AbstractModule {
+
+    @Override
+    public void configure() {
+        requireBinding(CloseableInjector.class);
+        MyJsr250Destroyer destroyer = new MyJsr250Destroyer();
+        requestInjection(destroyer);
+        bind(MyJsr250Destroyer.class).toInstance(destroyer);
+        bind(Jsr250KeyProvider.class).in(Singleton.class);
+        bind(Jsr250PostConstructHandler.class).in(Singleton.class);
+        bind(new TypeLiteral<MethodHandler<PreDestroy>>() {
+        }).to(Jsr250PreDestroyHandler.class).in(Singleton.class);
+        MBinder.wrap(binder()).bindAnnotationInjector(Resource.class, Jsr250KeyProvider.class)
+                .handleMethodAfterInjection(PostConstruct.class, Jsr250PostConstructHandler.class);
+    }
+
+    static class MyJsr250Destroyer implements InjectorCloseListener {
+        @Inject
+        Injector injector;
+
+        @Inject
+        MethodHandler<PreDestroy> destroyer;
+
+        @Override
+        public void onInjectorClosing() {
+            Map<Key<?>, Binding<?>> bindings = injector.getAllBindings();
+            Multimap<Binding<?>, Binding<?>> dependants = Multimaps.newSetMultimap(
+                    new IdentityHashMap<Binding<?>, Collection<Binding<?>>>(), new Supplier<Set<Binding<?>>>() {
+                        @Override
+                        public Set<Binding<?>> get() {
+                            return new HashSet<Binding<?>>();
+                        }
+                    });
+            for (Binding<?> binding : bindings.values()) {
+                if (binding instanceof HasDependencies) {
+                    for (Dependency<?> dependency : ((HasDependencies) binding).getDependencies()) {
+                        if (bindings.containsKey(dependency.getKey())) {
+                            dependants.put(injector.getBinding(dependency.getKey()), binding);
+                        }
+                    }
+                }
+            }
+            Map<Object, Object> done = new IdentityHashMap<Object, Object>(bindings.size());
+            for (final Binding<?> binding : bindings.values()) {
+                if (Scopes.isSingleton(binding)) {
+                    close(binding, done, dependants);
+                }
+            }
+            for (Scope scope : injector.getScopeBindings().values()) {
+                preDestroy(scope);
+            }
+        }
+
+        @SuppressFBWarnings("REC_CATCH_EXCEPTION")
+        @SuppressWarnings("illegalCatch")
+        private void close(Binding<?> binding, Map<Object, Object> done, Multimap<Binding<?>, Binding<?>> dependants) {
+            if (!done.containsKey(binding)) {
+                done.put(binding, Void.TYPE);
+                for (Binding<?> dependant : dependants.get(binding)) {
+                    close(dependant, done, dependants);
+                }
+                try {
+                    if (binding instanceof ProviderInstanceBinding<?>) {
+                        Object obj = ((ProviderInstanceBinding) binding).getProviderInstance();
+                        if (!done.containsKey(obj)) {
+                            preDestroy(obj);
+                            done.put(obj, Void.TYPE);
+                        }
+                    } else if (Scopes.isSingleton(binding)) {
+                        Object obj = binding.getProvider().get();
+                        if (!done.containsKey(obj)) {
+                            preDestroy(obj);
+                            done.put(obj, Void.TYPE);
+                        }
+                    }
+                } catch (Exception ex) {
+                    // just ignore close errors
+                }
+            }
+        }
+
+        private void preDestroy(Object instance) {
+            TypeLiteral<?> type = TypeLiteral.get(Reflect.getTargetClass(instance));
+            for (Method method : Reflect.findAllAnnotatedMethods(type.getRawType(), PreDestroy.class)) {
+                destroyer.handle(type, instance, method, method.getAnnotation(PreDestroy.class));
+            }
+        }
+    }
+
+}