View Javadoc

1   package com.atlassian.plugin.tracker;
2   
3   import static com.google.common.collect.Iterables.filter;
4   import static com.google.common.collect.Iterables.transform;
5   import static com.google.common.collect.Iterables.unmodifiableIterable;
6   import static java.util.Collections.singleton;
7   
8   import com.atlassian.plugin.ModuleDescriptor;
9   import com.atlassian.plugin.PluginAccessor;
10  import com.atlassian.plugin.event.PluginEventListener;
11  import com.atlassian.plugin.event.PluginEventManager;
12  import com.atlassian.plugin.event.events.PluginDisabledEvent;
13  import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
14  import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
15  
16  import com.google.common.base.Function;
17  
18  import java.util.concurrent.CopyOnWriteArraySet;
19  
20  /**
21   * Tracks enabled plugin module descriptors, focusing on fast reads
22   *
23   * @since 2.6.0
24   */
25  public class DefaultPluginModuleTracker<M, T extends ModuleDescriptor<M>> implements PluginModuleTracker<M, T>
26  {
27      private final PluginEventManager pluginEventManager;
28      private final Class<T> moduleDescriptorClass;
29      private final Customizer<M, T> pluginModuleTrackerCustomizer;
30      private final CopyOnWriteArraySet<T> moduleDescriptors = new CopyOnWriteArraySet<T>();
31      private final ModuleTransformer<M, T> moduleTransformer = new ModuleTransformer<M, T>();
32  
33      //
34      // ctors
35      //
36  
37      public DefaultPluginModuleTracker(final PluginAccessor pluginAccessor, final PluginEventManager pluginEventManager, final Class<T> moduleDescriptorClass)
38      {
39          this(pluginAccessor, pluginEventManager, moduleDescriptorClass, new NoOpPluginModuleTrackerCustomizer<M, T>());
40      }
41  
42      public DefaultPluginModuleTracker(final PluginAccessor pluginAccessor, final PluginEventManager pluginEventManager, final Class<T> moduleDescriptorClass, final Customizer<M, T> pluginModuleTrackerCustomizer)
43      {
44          this.pluginEventManager = pluginEventManager;
45          this.moduleDescriptorClass = moduleDescriptorClass;
46          this.pluginModuleTrackerCustomizer = pluginModuleTrackerCustomizer;
47          pluginEventManager.register(this);
48          addDescriptors(pluginAccessor.getEnabledModuleDescriptorsByClass(moduleDescriptorClass));
49      }
50  
51      //
52      // PluginModuleTracker impl
53      //
54  
55      public Iterable<T> getModuleDescriptors()
56      {
57          return unmodifiableIterable(moduleDescriptors);
58      }
59  
60      public Iterable<M> getModules()
61      {
62          return transform(getModuleDescriptors(), moduleTransformer);
63      }
64  
65      public int size()
66      {
67          return moduleDescriptors.size();
68      }
69  
70      public void close()
71      {
72          pluginEventManager.unregister(this);
73      }
74  
75      //
76      // plugin event listening
77      //
78  
79      @PluginEventListener
80      public void onPluginModuleEnabled(final PluginModuleEnabledEvent event)
81      {
82          addDescriptors(singleton((ModuleDescriptor<?>) event.getModule()));
83      }
84  
85      @PluginEventListener
86      public void onPluginModuleDisabled(final PluginModuleDisabledEvent event)
87      {
88          removeDescriptors(singleton((ModuleDescriptor<?>) event.getModule()));
89      }
90  
91      @PluginEventListener
92      public void onPluginDisabled(final PluginDisabledEvent event)
93      {
94          removeDescriptors(event.getPlugin().getModuleDescriptors());
95      }
96  
97      //
98      // module descriptor management
99      //
100 
101     private void addDescriptors(final Iterable<? extends ModuleDescriptor<?>> descriptors)
102     {
103         for (final T descriptor : filtered(descriptors))
104         {
105             final T customized = pluginModuleTrackerCustomizer.adding(descriptor);
106             if (customized != null)
107             {
108                 moduleDescriptors.add(customized);
109             }
110         }
111     }
112 
113     private void removeDescriptors(final Iterable<? extends ModuleDescriptor<?>> descriptors)
114     {
115         for (final T descriptor : filtered(descriptors))
116         {
117             if (moduleDescriptors.remove(descriptor))
118             {
119                 pluginModuleTrackerCustomizer.removed(descriptor);
120             }
121         }
122     }
123 
124     /**
125      * The descriptors that match the supplied class.
126      */
127     private Iterable<T> filtered(final Iterable<? extends ModuleDescriptor<?>> descriptors)
128     {
129         return filter(descriptors, moduleDescriptorClass);
130     }
131 
132     //
133     // inner classes
134     //
135 
136     private static class NoOpPluginModuleTrackerCustomizer<M, T extends ModuleDescriptor<M>> implements PluginModuleTracker.Customizer<M, T>
137     {
138         public T adding(final T descriptor)
139         {
140             return descriptor;
141         }
142 
143         public void removed(final T descriptor)
144         {}
145     }
146 
147     /**
148      * Safely get the Module from a {@link ModuleDescriptor}.
149      */
150     private static class ModuleTransformer<M, T extends ModuleDescriptor<M>> implements Function<T, M>
151     {
152         public M apply(final T from)
153         {
154             return from.getModule();
155         }
156     }
157 
158     /**
159      * Static factory method for constructing trackers generically where M is not known.
160      *
161      * @param <M> The module class, generically inferred.
162      * @param <T> The module descriptor class.
163      * @param pluginAccessor For getting the enabled descriptors of a certain type.
164      * @param pluginEventManager For being told about changes to the enabled plugins.
165      * @param moduleDescriptorClass The type of module descriptors we are interested in.
166      * @return a PluginModuleTracker useful for fast and upd to date caching of the currently enabled module descriptors.
167      * @since 2.7.0
168      */
169     public static <M, T extends ModuleDescriptor<M>> PluginModuleTracker<M, T> create(final PluginAccessor pluginAccessor, final PluginEventManager pluginEventManager, final Class<? extends ModuleDescriptor<?>> moduleDescriptorClass)
170     {
171         @SuppressWarnings("unchecked")
172         final Class<T> klass = (Class<T>) moduleDescriptorClass;
173         return new DefaultPluginModuleTracker<M, T>(pluginAccessor, pluginEventManager, klass);
174     }
175 }