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 }