1   package com.atlassian.config.lifecycle;
2   
3   import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginParseException;
6   import com.atlassian.plugin.StateAware;
7   import com.atlassian.plugin.module.ModuleFactory;
8   import com.atlassian.spring.container.ContainerManager;
9   import org.dom4j.Element;
10  import org.dom4j.Attribute;
11  
12  import javax.servlet.ServletContextListener;
13  
14  /**
15   * Descriptor for lifecycle plugin modules.
16   *
17   * <p>A lifecycle plugin module must either implement {@link LifecycleItem}, or {@link ServletContextListener}. The
18   * latter will automatically be wrapped in a {@link ServletContextListenerWrapper} by the descriptor, so
19   * {@link #getModule()} will <i>always</i> return a LifecycleItem instance.
20   *
21   * <p>Each module has a sequence number. On startup, the modules will be invoked in ascending order of sequence (lowest
22   * to highest), and then on shutdown, the order will be reversed.
23   */
24  public class LifecyclePluginModuleDescriptor extends AbstractModuleDescriptor implements Comparable
25  {
26      private Object module;
27      private int sequence;
28  
29      /**
30       * Default no-arg constructor
31       */
32      public LifecyclePluginModuleDescriptor(final ModuleFactory moduleFactory)
33      {
34          super(moduleFactory);
35      }
36  
37      /**
38       * Helpful constructor for tests
39       */
40      LifecyclePluginModuleDescriptor(final ModuleFactory moduleFactory, Object module, int sequence)
41      {
42          super(moduleFactory);
43          this.module = module;
44          this.sequence = sequence;
45      }
46  
47      public void init(Plugin plugin, Element element) throws PluginParseException
48      {
49          super.init(plugin, element);
50          sequence = determineSequenceNumber(element);
51      }
52  
53      private void ensureCompatibleModuleType() throws PluginParseException
54      {
55          Class moduleClass = getModuleClass();
56          if (!LifecycleItem.class.isAssignableFrom(moduleClass) && !ServletContextListener.class.isAssignableFrom(moduleClass))
57              throw new PluginParseException("Lifecycle classes must extend LifecycleItem or ServletContextListener. Module class: " + moduleClass.getName());
58      }
59  
60      private int determineSequenceNumber(Element element) throws PluginParseException
61      {
62          Attribute att = element.attribute("sequence");
63          if (att != null)
64          {
65              String value = att.getValue();
66              try
67              {
68                  return Integer.parseInt(value);
69              }
70              catch (NumberFormatException e)
71              {
72                  throw new PluginParseException("Could not determine sequence from: " + value);
73              }
74          }
75  
76          throw new PluginParseException("Missing required attribute: sequence");
77      }
78  
79      public Object getModule()
80      {
81          return module;
82      }
83  
84      private Object makeModule()
85      {
86          Object module = ContainerManager.getInstance().getContainerContext().createComponent(getModuleClass());
87  
88          if (module instanceof ServletContextListener)
89              module = new ServletContextListenerWrapper((ServletContextListener) module);
90  
91          return module;
92      }
93  
94      public void enabled()
95      {
96          super.enabled();
97          ensureCompatibleModuleType();
98          module = makeModule();
99          if  (module instanceof StateAware)
100             ((StateAware) module).enabled();
101     }
102 
103     public void disabled()
104     {
105         if  (module instanceof StateAware)
106             ((StateAware) module).disabled();
107         module = null;
108         super.disabled();
109     }
110 
111     public int getSequence()
112     {
113         return sequence;
114     }
115 
116     public int compareTo(Object o)
117     {
118         int otherSequence = ((LifecyclePluginModuleDescriptor)o).sequence;
119 
120         return (sequence == otherSequence) ? 0 : (sequence < otherSequence) ? -1 : 1;
121     }
122 }