1   package com.atlassian.config.lifecycle;
2   
3   import com.atlassian.config.lifecycle.events.ApplicationStartedEvent;
4   import com.atlassian.config.lifecycle.events.ApplicationStoppedEvent;
5   import com.atlassian.config.lifecycle.events.ApplicationStoppingEvent;
6   import com.atlassian.event.api.EventPublisher;
7   import com.atlassian.johnson.event.Event;
8   import com.atlassian.johnson.event.EventLevel;
9   import com.atlassian.johnson.event.EventType;
10  import com.atlassian.plugin.PluginAccessor;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import javax.servlet.ServletContext;
15  import java.util.Collections;
16  import java.util.List;
17  
18  import static com.google.common.collect.Lists.newArrayList;
19  
20  public class DefaultLifecycleManager implements LifecycleManager
21  {
22      private static final Logger log = LoggerFactory.getLogger(LifecycleManager.class);
23  
24      private PluginAccessor pluginAccessor;
25      private EventPublisher eventPublisher;
26      private boolean startedUp;
27  
28      public void startUp(ServletContext servletContext)
29      {
30          final List<LifecyclePluginModuleDescriptor> moduleDescriptors = getLifecyclePluginModuleDescriptors();
31          final LifecycleContext context = new DefaultLifecycleContext(servletContext);
32  
33          LifecyclePluginModuleDescriptor currentDescriptor = null;
34          try
35          {
36              for (LifecyclePluginModuleDescriptor descriptor : moduleDescriptors)
37              {
38                  currentDescriptor = descriptor;
39                  log.info("Starting: " + descriptor);
40                  ((LifecycleItem) descriptor.getModule()).startup(context);
41              }
42  
43              eventPublisher.publish(new ApplicationStartedEvent(this));
44              startedUp = true;
45          }
46          catch (Throwable t)
47          {
48              panicAndShutdown(t, context, currentDescriptor);
49          }
50      }
51  
52      public void shutDown(ServletContext servletContext)
53      {
54          shutDown(servletContext, null);
55      }
56  
57      public boolean isStartedUp()
58      {
59          return startedUp;
60      }
61  
62      private void panicAndShutdown(Throwable t, LifecycleContext context, LifecyclePluginModuleDescriptor descriptor)
63      {
64          final String errorString = "Unable to start up Confluence. Fatal error during startup sequence: " + descriptor + " - " + t;
65          log.error(errorString, t);
66          context.getAgentJohnson().addEvent(new Event(EventType.get("startup"), errorString, EventLevel.FATAL));
67          shutDown(context.getServletContext(), descriptor.getCompleteKey());
68      }
69  
70      private void shutDown(ServletContext servletContext, String startingPluginKey)
71      {
72          eventPublisher.publish(new ApplicationStoppingEvent(this));
73  
74          final List<LifecyclePluginModuleDescriptor> moduleDescriptors = getLifecyclePluginModuleDescriptors();
75          Collections.reverse(moduleDescriptors);
76          final LifecycleContext context = new DefaultLifecycleContext(servletContext);
77  
78          boolean started = startingPluginKey == null;
79  
80          for (LifecyclePluginModuleDescriptor descriptor : moduleDescriptors)
81          {
82              if (!started)
83              {
84                  if (descriptor.getCompleteKey().equals(startingPluginKey))
85                  {
86                      started = true;
87                  }
88                  else
89                  {
90                      continue;
91                  }
92              }
93  
94              log.info("Shutting down: " + descriptor);
95              final LifecycleItem item = (LifecycleItem) descriptor.getModule();
96              try
97              {
98                  item.shutdown(context);
99              }
100             catch (Throwable t)
101             {
102                 log.error("Error running shutdown plugin: " + descriptor.getDescription() + " - " + t, t);
103             }
104         }
105 
106         eventPublisher.publish(new ApplicationStoppedEvent(this));
107     }
108 
109     private List<LifecyclePluginModuleDescriptor> getLifecyclePluginModuleDescriptors()
110     {
111         final List<LifecyclePluginModuleDescriptor> modules = newArrayList(
112             pluginAccessor.getEnabledModuleDescriptorsByClass(LifecyclePluginModuleDescriptor.class));
113         Collections.sort(modules);
114         return modules;
115     }
116 
117     public void setPluginAccessor(PluginAccessor pluginAccessor)
118     {
119         this.pluginAccessor = pluginAccessor;
120     }
121 
122     public void setEventPublisher(EventPublisher eventPublisher)
123     {
124         this.eventPublisher = eventPublisher;
125     }
126 }