View Javadoc

1   package com.atlassian.plugin.main;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.LinkedList;
6   import java.util.List;
7   import java.util.Set;
8   import java.util.concurrent.atomic.AtomicReference;
9   
10  import com.atlassian.event.api.EventPublisher;
11  import com.atlassian.plugin.Application;
12  import com.atlassian.plugin.PluginAccessor;
13  import com.atlassian.plugin.PluginController;
14  import com.atlassian.plugin.PluginParseException;
15  import com.atlassian.plugin.SplitStartupPluginSystemLifecycle;
16  import com.atlassian.plugin.event.PluginEventListener;
17  import com.atlassian.plugin.event.PluginEventManager;
18  import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
19  import com.atlassian.plugin.event.events.PluginFrameworkStartedEvent;
20  import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
21  import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
22  import com.atlassian.plugin.factories.PluginFactory;
23  import com.atlassian.plugin.loaders.BundledPluginLoader;
24  import com.atlassian.plugin.loaders.ClassPathPluginLoader;
25  import com.atlassian.plugin.loaders.DirectoryPluginLoader;
26  import com.atlassian.plugin.loaders.PluginLoader;
27  import com.atlassian.plugin.manager.DefaultPluginManager;
28  import com.atlassian.plugin.osgi.container.OsgiContainerManager;
29  import com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager;
30  import com.atlassian.plugin.osgi.factory.OsgiBundleFactory;
31  import com.atlassian.plugin.osgi.factory.OsgiPluginFactory;
32  import com.atlassian.plugin.osgi.factory.RemotablePluginFactory;
33  import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
34  import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
35  import com.atlassian.plugin.repositories.FilePluginInstaller;
36  
37  import com.google.common.collect.ImmutableSet;
38  import com.google.common.collect.Sets;
39  
40  /**
41   * Facade interface to the Atlassian Plugins framework.  See the package Javadocs for usage information.
42   */
43  public class AtlassianPlugins
44  {
45      private OsgiContainerManager osgiContainerManager;
46      private DefaultPluginEventManager pluginEventManager;
47      private DefaultPluginManager pluginManager;
48      private HotDeployer hotDeployer;
49      private EventPublisher eventPublisher;
50  
51      /**
52       * Suffix for temporary directories which will be removed on shutdown
53       */
54      public static final String TEMP_DIRECTORY_SUFFIX = ".tmp";
55  
56      /**
57       * Constructs an instance of the plugin framework with the specified config.  No additional validation is performed on
58       * the configuration, so it is recommended you use the {@link PluginsConfigurationBuilder} class to create a
59       * configuration instance.
60       *
61       * @param config The plugins configuration to use
62       */
63      public AtlassianPlugins(final PluginsConfiguration config)
64      {
65          pluginEventManager = new DefaultPluginEventManager();
66          eventPublisher = pluginEventManager.getEventPublisher();
67  
68          final AtomicReference<PluginAccessor> pluginManagerRef = new AtomicReference<PluginAccessor>();
69          osgiContainerManager = new FelixOsgiContainerManager(
70                  config.getOsgiPersistentCache(),
71                  config.getPackageScannerConfiguration(),
72                  new CriticalHostComponentProvider(config.getHostComponentProvider(), pluginEventManager, pluginManagerRef),
73                  pluginEventManager);
74  
75          final Set<Application> applications = config.getApplication() != null ?
76                  Sets.newHashSet(config.getApplication()) : ImmutableSet.<Application>of();
77  
78          // plugin factories/deployers
79          final OsgiPluginFactory osgiPluginDeployer = new OsgiPluginFactory(
80                  config.getPluginDescriptorFilename(),
81                  applications,
82                  config.getOsgiPersistentCache(),
83                  osgiContainerManager,
84                  pluginEventManager);
85  
86          final OsgiBundleFactory osgiBundleDeployer = new OsgiBundleFactory(osgiContainerManager, pluginEventManager);
87  
88          final RemotablePluginFactory remotablePluginFactory = new RemotablePluginFactory(
89                  config.getPluginDescriptorFilename(),
90                  applications,
91                  osgiContainerManager,
92                  pluginEventManager);
93  
94          final List<PluginFactory> pluginDeployers = new LinkedList<PluginFactory>(Arrays.asList(osgiPluginDeployer, osgiBundleDeployer, remotablePluginFactory));
95          if (config.isUseLegacyDynamicPluginDeployer())
96          {
97              pluginDeployers.add(new LegacyDynamicPluginFactory(config.getPluginDescriptorFilename()));
98          }
99  
100         final List<PluginLoader> pluginLoaders = new ArrayList<PluginLoader>();
101 
102         // classpath plugins
103         pluginLoaders.add(new ClassPathPluginLoader());
104 
105         // bundled plugins
106         if (config.getBundledPluginUrl() != null)
107         {
108             pluginLoaders.add(new BundledPluginLoader(config.getBundledPluginUrl(), config.getBundledPluginCacheDirectory(), pluginDeployers, pluginEventManager));
109         }
110 
111         // osgi/v2 and v3 plugins
112         pluginLoaders.add(new DirectoryPluginLoader(config.getPluginDirectory(), pluginDeployers, pluginEventManager));
113 
114         pluginManager = new DefaultPluginManager(
115                 config.getPluginStateStore(),
116                 pluginLoaders,
117                 config.getModuleDescriptorFactory(),
118                 pluginEventManager);
119         pluginManagerRef.set(pluginManager);
120 
121         pluginManager.setPluginInstaller(new FilePluginInstaller(config.getPluginDirectory()));
122 
123         if (config.getHotDeployPollingPeriod() > 0)
124         {
125             hotDeployer = new HotDeployer(pluginManager, config.getHotDeployPollingPeriod());
126         }
127     }
128 
129     public void afterPropertiesSet()
130     {
131         pluginEventManager.register(this);
132     }
133 
134     public void destroy()
135     {
136         pluginEventManager.unregister(this);
137     }
138 
139     /**
140      * Starts the plugins framework.
141      *
142      * @throws PluginParseException If there was any problems parsing any of the plugins
143      * @deprecated Use {@link #afterPropertiesSet}, {@link #getPluginSystemLifecycle}.init().
144      */
145     @Deprecated
146     public void start() throws PluginParseException
147     {
148         afterPropertiesSet();
149         getPluginSystemLifecycle().init();
150     }
151 
152     /**
153      * Stops the framework.
154      *
155      * @deprecated Use {@link #getPluginSystemLifecycle}.shutdown(), {@link #destroy}.
156      */
157     @Deprecated
158     public void stop()
159     {
160         getPluginSystemLifecycle().shutdown();
161         destroy();
162     }
163 
164     /**
165      * @return the underlying OSGi container manager
166      */
167     public OsgiContainerManager getOsgiContainerManager()
168     {
169         return osgiContainerManager;
170     }
171 
172     /**
173      * @return the plugin event manager
174      */
175     public PluginEventManager getPluginEventManager()
176     {
177         return pluginEventManager;
178     }
179 
180     /**
181      * @return the event publisher used by plugin event manager
182      */
183     public EventPublisher getEventPublisher()
184     {
185         return eventPublisher;
186     }
187 
188     /**
189      * @return the plugin controller for manipulating plugins
190      */
191     public PluginController getPluginController()
192     {
193         return pluginManager;
194     }
195 
196     /**
197      * @return the plugin accessor for accessing plugins
198      */
199     public PluginAccessor getPluginAccessor()
200     {
201         return pluginManager;
202     }
203 
204     /**
205      * @return the plugin system lifecycle for starting and stopping the plugin system
206      */
207     public SplitStartupPluginSystemLifecycle getPluginSystemLifecycle()
208     {
209         return pluginManager;
210     }
211 
212 
213     @PluginEventListener
214     public void onPluginFrameworkStartedEvent(final PluginFrameworkStartedEvent event)
215     {
216         if (hotDeployer != null && !hotDeployer.isRunning())
217         {
218             hotDeployer.start();
219         }
220     }
221 
222     @PluginEventListener
223     public void onPluginFrameworkShutdownEvent(final PluginFrameworkShutdownEvent event)
224     {
225         if (hotDeployer != null && hotDeployer.isRunning())
226         {
227             hotDeployer.stop();
228         }
229     }
230 
231     private static class CriticalHostComponentProvider implements HostComponentProvider
232     {
233         private final HostComponentProvider delegate;
234         private final PluginEventManager pluginEventManager;
235         private final AtomicReference<PluginAccessor> pluginManagerRef;
236 
237         public CriticalHostComponentProvider(
238                 final HostComponentProvider delegate,
239                 final PluginEventManager pluginEventManager,
240                 final AtomicReference<PluginAccessor> pluginManagerRef)
241         {
242             this.delegate = delegate;
243             this.pluginEventManager = pluginEventManager;
244             this.pluginManagerRef = pluginManagerRef;
245         }
246 
247         public void provide(final ComponentRegistrar registrar)
248         {
249             registrar.register(PluginEventManager.class).forInstance(pluginEventManager);
250             registrar.register(PluginAccessor.class).forInstance(pluginManagerRef.get());
251             delegate.provide(registrar);
252         }
253     }
254 }