View Javadoc
1   package com.atlassian.plugin.spring.scanner.dynamic.contexts;
2   
3   import com.atlassian.event.api.EventPublisher;
4   import com.atlassian.plugin.event.events.PluginContainerRefreshedEvent;
5   import com.atlassian.plugin.osgi.spring.DefaultSpringContainerAccessor;
6   import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
7   import org.osgi.framework.BundleContext;
8   import org.springframework.context.ApplicationContext;
9   import org.springframework.context.ConfigurableApplicationContext;
10  
11  import java.util.Date;
12  
13  /**
14   * This class can install new Spring application contexts into a running Atlassian plugin
15   */
16  public class ApplicationContextInstallerImpl implements DynamicContext.Installer {
17      private final EventPublisher eventPublisher;
18      private final BundleContext bundleContext;
19      private final String pluginKey;
20  
21      ApplicationContextInstallerImpl(final EventPublisher eventPublisher, final BundleContext bundleContext, final String pluginKey) {
22          this.eventPublisher = eventPublisher;
23          this.bundleContext = bundleContext;
24          this.pluginKey = pluginKey;
25      }
26  
27  
28      /**
29       * This method will create and install a new child application context into the plugin.
30       * <p>
31       * As a side effect a {@link com.atlassian.plugin.event.events.PluginRefreshedEvent} will be generated for this new
32       * child context.
33       * <p>
34       * By calling this method you are able to have the plugin auto-wire components such as actions and web-items from
35       * the child context instead of the originating parent context.  This will allow you to dynamically grow and shrink
36       * the components that your plugin gives off to the world based on external events such as licencing or memory
37       * passivisation.
38       *
39       * @param springConfigPaths the paths to find spring configuration files on the class path
40       * @param parentContext     the parent context, typically the context that came with your plugin
41       * @return the newly created child context
42       */
43      @Override
44      public ConfigurableApplicationContext useContext(String[] springConfigPaths, ApplicationContext parentContext) {
45          final Date now = new Date();
46          final OsgiBundleXmlApplicationContext newContext = new GeminiOsgiBundleXmlApplicationContext(springConfigPaths, parentContext);
47  
48          newContext.setDisplayName(bundleContext.getBundle().getSymbolicName());
49          newContext.setId(bundleContext.getBundle().getBundleId() + "." + now.toString());
50          newContext.setBundleContext(bundleContext);
51          newContext.setPublishContextAsService(false);
52          newContext.refresh();
53          newContext.start();
54  
55          publishNewContext(newContext);
56  
57          return newContext;
58      }
59  
60      /**
61       * This method can "close" a child application context (typically one created with {@link #useContext(String[],
62       * org.springframework.context.ApplicationContext)} and set in the replacement application context instead.
63       * Typically the replacement would be the parent of the child context to be closed but it doesnt always have to be.
64       *
65       * @param childContext       the child context to close.
66       * @param replacementContext the context to replace the child context with.  Typically this can be its parent
67       */
68      @Override
69      public void closeAndUseContext(ConfigurableApplicationContext childContext, ApplicationContext replacementContext) {
70          childContext.close();
71          if (replacementContext != null) {
72              publishNewContext(replacementContext);
73          }
74      }
75  
76      private void publishNewContext(final ApplicationContext newContext) {
77          //
78          // cause the OsgiPlugin to get our new context.  This is really important.  This is how it knows how
79          // to wire future code etc..
80          DefaultSpringContainerAccessor containerAccessor = new DefaultSpringContainerAccessor(newContext);
81          PluginContainerRefreshedEvent event = new PluginContainerRefreshedEvent(containerAccessor, pluginKey);
82  
83          eventPublisher.publish(event);
84      }
85  }