1 package com.atlassian.plugin.manager;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.Plugin;
5 import com.atlassian.plugin.PluginAccessor;
6 import com.atlassian.plugin.PluginController;
7 import com.atlassian.plugin.event.PluginEventListener;
8 import com.atlassian.plugin.event.PluginEventManager;
9 import com.atlassian.plugin.event.events.PluginDisabledEvent;
10 import com.atlassian.plugin.event.events.PluginEnabledEvent;
11 import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
12 import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
13 import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
14 import com.atlassian.plugin.instrumentation.PluginSystemInstrumentation;
15 import com.atlassian.plugin.instrumentation.Timer;
16 import com.atlassian.plugin.predicate.EnabledModulePredicate;
17 import com.atlassian.plugin.predicate.ModuleOfClassPredicate;
18 import com.google.common.cache.CacheLoader;
19 import com.google.common.cache.LoadingCache;
20
21 import javax.annotation.Nonnull;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.function.Predicate;
25 import java.util.stream.Collectors;
26
27 import static com.google.common.base.Preconditions.checkNotNull;
28 import static com.google.common.cache.CacheBuilder.newBuilder;
29 import static java.util.concurrent.TimeUnit.SECONDS;
30
31
32
33
34
35 public final class EnabledModuleCachingPluginAccessor extends ForwardingPluginAccessor implements PluginAccessor {
36 private static final long DESCRIPTOR_TIMEOUT_SEC = Long.getLong("com.atlassian.plugin.descriptor.class.cache.timeout.sec", 30 * 60);
37 private static final long MODULE_TIMEOUT_SEC = Long.getLong("com.atlassian.plugin.module.class.cache.timeout.sec", 30 * 60);
38
39 private final SafeModuleExtractor safeModuleExtractor;
40
41 private final LoadingCache<Class<ModuleDescriptor<Object>>, List<ModuleDescriptor<Object>>> cacheByDescriptorClass =
42 newBuilder()
43 .expireAfterAccess(DESCRIPTOR_TIMEOUT_SEC, SECONDS)
44 .build(new ByModuleDescriptorClassCacheLoader());
45
46 private final LoadingCache<Class<?>, List<ModuleDescriptor>> cacheByModuleClass =
47 newBuilder()
48 .expireAfterAccess(MODULE_TIMEOUT_SEC, SECONDS)
49 .build(new ByModuleClassCacheLoader());
50
51 public EnabledModuleCachingPluginAccessor(final PluginAccessor delegate, final PluginEventManager pluginEventManager, final PluginController pluginController) {
52 super(delegate);
53 checkNotNull(pluginEventManager);
54
55 this.safeModuleExtractor = new SafeModuleExtractor(pluginController);
56
57
58
59 pluginEventManager.register(this);
60 }
61
62
63
64
65
66
67
68 @SuppressWarnings("unused")
69 @PluginEventListener
70 public void onPluginDisable(PluginDisabledEvent event) {
71
72 invalidateAll();
73 }
74
75
76
77
78 @SuppressWarnings("unused")
79 @PluginEventListener
80 public void onPluginEnable(PluginEnabledEvent event) {
81
82 invalidateAll();
83 }
84
85 @SuppressWarnings("unused")
86 @PluginEventListener
87 public void onPluginModuleEnabled(final PluginModuleEnabledEvent event) {
88
89
90
91
92
93
94
95 invalidateAll();
96 }
97
98 @SuppressWarnings("unused")
99 @PluginEventListener
100 public void onPluginModuleDisabled(final PluginModuleDisabledEvent event) {
101
102
103
104
105
106
107
108 invalidateAll();
109 }
110
111 @SuppressWarnings("unused")
112 @PluginEventListener
113 public void onPluginFrameworkShutdown(final PluginFrameworkShutdownEvent event) {
114 invalidateAll();
115 }
116
117 private void invalidateAll() {
118 cacheByDescriptorClass.invalidateAll();
119 cacheByModuleClass.invalidateAll();
120 }
121
122
123
124
125 private class ByModuleDescriptorClassCacheLoader extends CacheLoader<Class<ModuleDescriptor<Object>>, List<ModuleDescriptor<Object>>> {
126 public List<ModuleDescriptor<Object>> load(@Nonnull final Class<ModuleDescriptor<Object>> moduleDescriptorClass) {
127 return delegate.getEnabledModuleDescriptorsByClass(moduleDescriptorClass);
128 }
129 }
130
131
132
133
134 private class ByModuleClassCacheLoader extends CacheLoader<Class, List<ModuleDescriptor>> {
135 @SuppressWarnings("unchecked")
136 public List<ModuleDescriptor> load(@Nonnull final Class moduleClass) {
137 return getEnabledModuleDescriptorsByModuleClass(moduleClass);
138 }
139 }
140
141
142
143
144
145
146
147
148
149 @SuppressWarnings("unchecked")
150 @Override
151 public <D extends ModuleDescriptor<?>> List<D> getEnabledModuleDescriptorsByClass(final Class<D> descriptorClazz) {
152 try (Timer ignored = PluginSystemInstrumentation.instance().pullTimer("getEnabledModuleDescriptorsByClass")) {
153 final List<ModuleDescriptor<Object>> descriptors =
154 cacheByDescriptorClass.getUnchecked((Class<ModuleDescriptor<Object>>) descriptorClazz);
155 return (List<D>) descriptors;
156 }
157 }
158
159
160
161
162
163
164
165
166
167 @Override
168 public <M> List<M> getEnabledModulesByClass(final Class<M> moduleClass) {
169 try (Timer ignored = PluginSystemInstrumentation.instance().pullTimer("getEnabledModulesByClass")) {
170 List<?> descriptors = cacheByModuleClass.getUnchecked(moduleClass);
171
172 return safeModuleExtractor.getModules((List<ModuleDescriptor<M>>) descriptors);
173 }
174 }
175
176
177
178
179
180
181
182
183 private <M> List<ModuleDescriptor<M>> getEnabledModuleDescriptorsByModuleClass(final Class<M> moduleClass) {
184 final ModuleOfClassPredicate<M> ofType = new ModuleOfClassPredicate<>(moduleClass);
185 final EnabledModulePredicate enabled = new EnabledModulePredicate();
186 return getModuleDescriptors(delegate.getEnabledPlugins(), ofType.and(enabled));
187 }
188
189
190
191
192
193
194
195
196
197 private <M> List<ModuleDescriptor<M>> getModuleDescriptors(final Collection<Plugin> plugins,
198 final Predicate<ModuleDescriptor<M>> predicate) {
199
200 return plugins.stream()
201 .flatMap(plugin -> plugin.getModuleDescriptors().stream())
202 .map(moduleDescriptor -> (ModuleDescriptor<M>) moduleDescriptor)
203 .filter(predicate)
204 .collect(Collectors.toList());
205 }
206 }