1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  package org.grouplens.grapht;
21  
22  import com.google.common.base.Throwables;
23  import com.google.common.util.concurrent.UncheckedExecutionException;
24  import org.apache.commons.lang3.reflect.MethodUtils;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  import javax.annotation.PreDestroy;
29  import java.lang.reflect.InvocationTargetException;
30  import java.lang.reflect.Method;
31  import java.util.Deque;
32  import java.util.LinkedList;
33  
34  public class LifecycleManager implements AutoCloseable {
35      private static final Logger logger = LoggerFactory.getLogger(LifecycleManager.class);
36      private Deque<TeardownAction> actions = new LinkedList<TeardownAction>();
37  
38      
39  
40  
41  
42  
43  
44      public void registerComponent(Object instance) {
45          if (instance == null) {
46              return;
47          }
48  
49          if (instance instanceof AutoCloseable) {
50              actions.add(new CloseAction((AutoCloseable) instance));
51          }
52          for (Method m: MethodUtils.getMethodsListWithAnnotation(instance.getClass(), PreDestroy.class)) {
53              actions.add(new PreDestroyAction(instance, m));
54          }
55      }
56  
57      
58  
59  
60      @Override
61      public void close() {
62          Throwable error = null;
63          while (!actions.isEmpty()) {
64              TeardownAction action = actions.removeFirst();
65              try {
66                  action.destroy();
67              } catch (Throwable th) {
68                  if (error == null) {
69                      error = th;
70                  } else {
71                      error.addSuppressed(th);
72                  }
73              }
74          }
75          if (error != null) {
76              throw Throwables.propagate(error);
77          }
78      }
79  
80      
81  
82  
83      interface TeardownAction {
84          void destroy();
85      }
86  
87      static class PreDestroyAction implements TeardownAction {
88          private final Object instance;
89          private final Method method;
90  
91          public PreDestroyAction(Object inst, Method m) {
92              instance = inst;
93              method = m;
94          }
95  
96          @Override
97          public void destroy() {
98              try {
99                  logger.debug("invoking pre-destroy method {} on {}", method, instance);
100                 method.invoke(instance);
101             } catch (IllegalAccessException e) {
102                 throw new RuntimeException("cannot access " + method, e);
103             } catch (InvocationTargetException e) {
104                 throw new UncheckedExecutionException("error invoking " + method, e);
105             }
106         }
107     }
108 
109     static class CloseAction implements TeardownAction {
110         private final AutoCloseable instance;
111 
112         public CloseAction(AutoCloseable inst) {
113             instance = inst;
114         }
115 
116         @Override
117         public void destroy() {
118             try {
119                 logger.debug("closing {}", instance);
120                 instance.close();
121             } catch (Exception e) {
122                 throw new UncheckedExecutionException("Error destroying " + instance, e);
123             }
124         }
125     }
126 }