View Javadoc

1   package com.atlassian.plugin.web.descriptors;
2   
3   import java.util.Iterator;
4   import java.util.List;
5   
6   import com.atlassian.plugin.hostcontainer.HostContainer;
7   import com.atlassian.plugin.util.Assertions;
8   import org.dom4j.Element;
9   
10  import com.atlassian.plugin.Plugin;
11  import com.atlassian.plugin.PluginParseException;
12  import com.atlassian.plugin.loaders.LoaderUtils;
13  import com.atlassian.plugin.web.Condition;
14  import com.atlassian.plugin.web.conditions.AbstractCompositeCondition;
15  import com.atlassian.plugin.web.conditions.AndCompositeCondition;
16  import com.atlassian.plugin.web.conditions.ConditionLoadingException;
17  import com.atlassian.plugin.web.conditions.InvertedCondition;
18  import com.atlassian.plugin.web.conditions.OrCompositeCondition;
19  
20  /**
21   * This class contains the logic for constructing
22   * {@link com.atlassian.plugin.web.Condition} objects from a module descriptor's
23   * XML element. Its functionality is used by both
24   * {@link com.atlassian.plugin.web.descriptors.AbstractWebFragmentModuleDescriptor}
25   * and
26   * {@link com.atlassian.plugin.web.descriptors.DefaultWebPanelModuleDescriptor}.
27   * 
28   * @since 2.5.0
29   */
30  public class ConditionElementParser
31  {
32      public static class CompositeType
33      {
34          public static final int OR = 0;
35          public static final int AND = 1;
36  
37          public static int parse(final String type) throws PluginParseException
38          {
39              if ("or".equalsIgnoreCase(type))
40              {
41                  return CompositeType.OR;
42              }
43              else if ("and".equalsIgnoreCase(type))
44              {
45                  return CompositeType.AND;
46              }
47              else
48              {
49                  throw new PluginParseException("Invalid condition type specified. type = " + type);
50              }
51          }
52      }
53  
54      /**
55       * Creates a condition.  Only temporary until conditions for web fragments can be converted to use {@link HostContainer}
56       */
57      public static interface ConditionFactory
58      {
59          Condition create(String className, Plugin plugin) throws ConditionLoadingException;
60      }
61  
62      private final ConditionFactory conditionFactory;
63  
64      public ConditionElementParser(ConditionFactory conditionFactory)
65      {
66          this.conditionFactory = conditionFactory;
67      }
68  
69      /**
70       * Create a condition for when this web fragment should be displayed.
71       * 
72       * @param element Element of web-section, web-item, or web-panel.
73       * @param type logical operator type
74       * @throws com.atlassian.plugin.PluginParseException
75       */
76      @SuppressWarnings("unchecked")
77      public Condition makeConditions(final Plugin plugin, final Element element, final int type) throws PluginParseException
78      {
79          Assertions.notNull("plugin == null", plugin);
80  
81          // make single conditions (all Anded together)
82          final List<Element> singleConditionElements = element.elements("condition");
83          Condition singleConditions = null;
84          if ((singleConditionElements != null) && !singleConditionElements.isEmpty())
85          {
86              singleConditions = makeConditions(plugin, singleConditionElements, type);
87          }
88  
89          // make composite conditions (logical operator can be specified by
90          // "type")
91          final List<Element> nestedConditionsElements = element.elements("conditions");
92          AbstractCompositeCondition nestedConditions = null;
93          if ((nestedConditionsElements != null) && !nestedConditionsElements.isEmpty())
94          {
95              nestedConditions = getCompositeCondition(type);
96              for (final Iterator<Element> iterator = nestedConditionsElements.iterator(); iterator.hasNext();)
97              {
98                  final Element nestedElement = iterator.next();
99                  nestedConditions.addCondition(makeConditions(plugin, nestedElement, CompositeType.parse(nestedElement.attributeValue("type"))));
100             }
101         }
102 
103         if ((singleConditions != null) && (nestedConditions != null))
104         {
105             // Join together the single and composite conditions by this type
106             final AbstractCompositeCondition compositeCondition = getCompositeCondition(type);
107             compositeCondition.addCondition(singleConditions);
108             compositeCondition.addCondition(nestedConditions);
109             return compositeCondition;
110         }
111         else if (singleConditions != null)
112         {
113             return singleConditions;
114         }
115         else if (nestedConditions != null)
116         {
117             return nestedConditions;
118         }
119 
120         return null;
121     }
122 
123     public Condition makeConditions(final Plugin plugin, final List<Element> elements, final int type) throws PluginParseException
124     {
125         if (elements.isEmpty())
126         {
127             return null;
128         }
129         else if (elements.size() == 1)
130         {
131             return makeCondition(plugin, elements.get(0));
132         }
133         else
134         {
135             final AbstractCompositeCondition compositeCondition = getCompositeCondition(type);
136             for (final Iterator<Element> it = elements.iterator(); it.hasNext();)
137             {
138                 final Element element = it.next();
139                 compositeCondition.addCondition(makeCondition(plugin, element));
140             }
141 
142             return compositeCondition;
143         }
144     }
145 
146     public Condition makeCondition(final Plugin plugin, final Element element) throws PluginParseException
147     {
148         try
149         {
150             final Condition condition = conditionFactory.create(element.attributeValue("class"), plugin);
151             condition.init(LoaderUtils.getParams(element));
152 
153             if ((element.attribute("invert") != null) && "true".equals(element.attributeValue("invert")))
154             {
155                 return new InvertedCondition(condition);
156             }
157 
158             return condition;
159         }
160         catch (final ClassCastException e)
161         {
162             throw new PluginParseException("Configured condition class does not implement the Condition interface", e);
163         }
164         catch (final ConditionLoadingException cle)
165         {
166             throw new PluginParseException("Unable to load the module's display conditions: " + cle.getMessage(), cle);
167         }
168     }
169 
170     private AbstractCompositeCondition getCompositeCondition(final int type) throws PluginParseException
171     {
172         switch (type)
173         {
174         case CompositeType.OR:
175             return new OrCompositeCondition();
176         case CompositeType.AND:
177             return new AndCompositeCondition();
178         default:
179             throw new PluginParseException("Invalid condition type specified. type = " + type);
180         }
181     }
182 }