View Javadoc

1   package com.atlassian.plugin.web.descriptors;
2   
3   import java.util.Iterator;
4   import java.util.List;
5   
6   import org.dom4j.Element;
7   
8   import com.atlassian.plugin.Plugin;
9   import com.atlassian.plugin.PluginParseException;
10  import com.atlassian.plugin.StateAware;
11  import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
12  import com.atlassian.plugin.loaders.LoaderUtils;
13  import com.atlassian.plugin.web.Condition;
14  import com.atlassian.plugin.web.ContextProvider;
15  import com.atlassian.plugin.web.WebInterfaceManager;
16  import com.atlassian.plugin.web.conditions.AbstractCompositeCondition;
17  import com.atlassian.plugin.web.conditions.AndCompositeCondition;
18  import com.atlassian.plugin.web.conditions.InvertedCondition;
19  import com.atlassian.plugin.web.conditions.OrCompositeCondition;
20  import com.atlassian.plugin.web.model.DefaultWebLabel;
21  import com.atlassian.plugin.web.model.DefaultWebParam;
22  import com.atlassian.plugin.web.model.WebLabel;
23  import com.atlassian.plugin.web.model.WebParam;
24  
25  /**
26   * An abstract convenience class for web fragment descriptors.
27   */
28  public abstract class AbstractWebFragmentModuleDescriptor extends AbstractModuleDescriptor implements StateAware, WebFragmentModuleDescriptor
29  {
30      protected WebInterfaceManager webInterfaceManager;
31      protected Element element;
32      protected int weight;
33      
34      protected Condition condition;
35      protected ContextProvider contextProvider;
36      protected DefaultWebLabel label;
37      protected DefaultWebLabel tooltip;
38      protected WebParam params;
39  
40      protected AbstractWebFragmentModuleDescriptor(WebInterfaceManager webInterfaceManager)
41      {
42          this.webInterfaceManager = webInterfaceManager;
43      }
44  
45      public AbstractWebFragmentModuleDescriptor()
46      {
47      }
48  
49      public void init(Plugin plugin, Element element) throws PluginParseException
50      {
51          super.init(plugin, element);
52  
53          this.element = element; 
54          weight = 1000;
55          try
56          {
57              weight = Integer.parseInt(element.attributeValue("weight"));
58          }
59          catch (NumberFormatException e)
60          {
61          }
62      }
63  
64      /**
65       * Create a condition for when this web fragment should be displayed
66       * @param element Element of web-section or web-item
67       * @param type logical operator type {@link #getCompositeType}
68       * @throws PluginParseException
69       */
70      protected Condition makeConditions(Element element, int type) throws PluginParseException
71      {
72          //make single conditions (all Anded together)
73          List singleConditionElements = element.elements("condition");
74          Condition singleConditions = null;
75          if (singleConditionElements != null && !singleConditionElements.isEmpty())
76          {
77              singleConditions = makeConditions(singleConditionElements, type);
78          }
79  
80          //make composite conditions (logical operator can be specified by "type")
81          List nestedConditionsElements = element.elements("conditions");
82          AbstractCompositeCondition nestedConditions = null;
83          if (nestedConditionsElements != null && !nestedConditionsElements.isEmpty())
84          {
85              nestedConditions = getCompositeCondition(type);
86              for (Iterator iterator = nestedConditionsElements.iterator(); iterator.hasNext();)
87              {
88                  Element nestedElement = (Element) iterator.next();
89                  nestedConditions.addCondition(makeConditions(nestedElement, getCompositeType(nestedElement.attributeValue("type"))));
90              }
91          }
92  
93          if (singleConditions != null && nestedConditions != null)
94          {
95              //Join together the single and composite conditions by this type
96              AbstractCompositeCondition compositeCondition = getCompositeCondition(type);
97              compositeCondition.addCondition(singleConditions);
98              compositeCondition.addCondition(nestedConditions);
99              return compositeCondition;
100         }
101         else if (singleConditions != null)
102         {
103             return singleConditions;
104         }
105         else if (nestedConditions != null)
106         {
107             return nestedConditions;
108         }
109 
110         return null;
111     }
112 
113     protected Condition makeConditions(List elements, int type) throws PluginParseException
114     {
115         if (elements.size() == 0)
116         {
117             return null;
118         }
119         else if (elements.size() == 1)
120         {
121             return makeCondition((Element) elements.get(0));
122         }
123         else
124         {
125             AbstractCompositeCondition compositeCondition = getCompositeCondition(type);
126             for (Iterator it = elements.iterator(); it.hasNext();)
127             {
128                 Element element = (Element) it.next();
129                 compositeCondition.addCondition(makeCondition(element));
130             }
131 
132             return compositeCondition;
133         }
134     }
135 
136     protected Condition makeCondition(Element element) throws PluginParseException
137     {
138         try
139         {
140             Condition condition = webInterfaceManager.getWebFragmentHelper().loadCondition(element.attributeValue("class"), plugin);
141             condition.init(LoaderUtils.getParams(element));
142 
143             if (element.attribute("invert") != null && "true".equals(element.attributeValue("invert")))
144             {
145                 return new InvertedCondition(condition);
146             }
147 
148             return condition;
149         }
150         catch (ClassCastException e)
151         {
152             throw new PluginParseException("Configured condition class does not implement the Condition interface");
153         }
154         catch (Throwable t)
155         {
156             throw new PluginParseException(t);
157         }
158     }
159 
160     protected ContextProvider makeContextProvider(Element element) throws PluginParseException
161     {
162         try
163         {
164             ContextProvider context = webInterfaceManager.getWebFragmentHelper().loadContextProvider(element.attributeValue("class"), plugin);
165             context.init(LoaderUtils.getParams(element));
166 
167             return context;
168         }
169         catch (ClassCastException e)
170         {
171             throw new PluginParseException("Configured context-provider class does not implement the ContextProvider interface");
172         }
173         catch (Throwable t)
174         {
175             throw new PluginParseException(t);
176         }
177     }
178 
179     private int getCompositeType(String type) throws PluginParseException
180     {
181         if ("or".equalsIgnoreCase(type))
182         {
183             return COMPOSITE_TYPE_OR;
184         }
185         else if ("and".equalsIgnoreCase(type))
186         {
187             return COMPOSITE_TYPE_AND;
188         }
189         throw new PluginParseException("Invalid condition type specified. type = " + type);
190     }
191 
192     private AbstractCompositeCondition getCompositeCondition(int type) throws PluginParseException
193     {
194         switch (type)
195         {
196             case COMPOSITE_TYPE_OR:
197             {
198                 return new OrCompositeCondition();
199             }
200             case COMPOSITE_TYPE_AND:
201             {
202                 return new AndCompositeCondition();
203             }
204         }
205         throw new PluginParseException("Invalid condition type specified. type = " + type);
206     }
207 
208     public void enabled()
209     {
210         // this was moved to the enabled() method because spring beans declared
211         // by the plugin are not available for injection during the init() phase
212         try
213         {
214             if (element.element("context-provider") != null)
215             {
216                 contextProvider = makeContextProvider(element.element("context-provider"));
217             }
218     
219             if (element.element("label") != null)
220             {
221                 label = new DefaultWebLabel(element.element("label"), webInterfaceManager.getWebFragmentHelper(), contextProvider, this);
222             }
223     
224             if (element.element("tooltip") != null)
225             {
226                 tooltip = new DefaultWebLabel(element.element("tooltip"), webInterfaceManager.getWebFragmentHelper(), contextProvider, this);
227             }
228     
229             if (getParams() != null)
230             {
231                 params = new DefaultWebParam(getParams(), webInterfaceManager.getWebFragmentHelper(), contextProvider, this);
232             }
233     
234             condition = makeConditions(element, COMPOSITE_TYPE_AND);
235         }
236         catch (PluginParseException e)
237         {
238             // is there a better exception to throw?
239             throw new RuntimeException("Unable to enable web fragment", e);
240         }
241         
242         webInterfaceManager.refresh();
243     }
244 
245     public void disabled()
246     {
247         webInterfaceManager.refresh();
248     }
249 
250     public int getWeight()
251     {
252         return weight;
253     }
254 
255     public Object getModule()
256     {
257         return null;
258     }
259 
260     public WebLabel getWebLabel()
261     {
262         return label;
263     }
264 
265     public WebLabel getTooltip()
266     {
267         return tooltip;
268     }
269 
270     public void setWebInterfaceManager(WebInterfaceManager webInterfaceManager)
271     {
272         this.webInterfaceManager = webInterfaceManager;
273     }
274 
275     public Condition getCondition()
276     {
277         return condition;
278     }
279 
280     public ContextProvider getContextProvider()
281     {
282         return contextProvider;
283     }
284 
285     public WebParam getWebParams()
286     {
287         return params;
288     }
289 }