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