View Javadoc

1   package com.atlassian.plugin.servlet.descriptors;
2   
3   import com.atlassian.plugin.Plugin;
4   import com.atlassian.plugin.PluginParseException;
5   import com.atlassian.plugin.StateAware;
6   import com.atlassian.plugin.module.ModuleFactory;
7   import com.atlassian.plugin.servlet.ServletModuleManager;
8   import com.atlassian.plugin.servlet.filter.FilterDispatcherCondition;
9   import com.atlassian.plugin.servlet.filter.FilterLocation;
10  import com.atlassian.plugin.util.validation.ValidationPattern;
11  import com.google.common.collect.Sets;
12  import org.dom4j.Element;
13  
14  import javax.servlet.Filter;
15  import java.util.Arrays;
16  import java.util.Comparator;
17  import java.util.List;
18  import java.util.Set;
19  
20  import static com.atlassian.plugin.util.validation.ValidationPattern.test;
21  import static com.google.common.base.Preconditions.checkNotNull;
22  
23  /**
24   * A module descriptor that allows plugin developers to define servlet filters.  Developers can define what urls the
25   * filter should be applied to by defining one or more <url-pattern> elements and they can decide where in the
26   * filter stack a plugin filter should go by defining the "location" and "weight" attributes.
27   * <p/>
28   * The location attribute can have one of four values:
29   * </p>
30   * <ul>
31   * <li>after-encoding - after the character encoding filter</li>
32   * <li>before-login - before the login filter</li>
33   * <li>before-decoration - before any global decoration like sitemesh</li>
34   * <li>before-dispatch - before any dispatching filters or servlets</li>
35   * </ul>
36   * <p>
37   * The default for the location attribute is "before-dispatch".
38   * <p/>
39   * The weight attribute can have any integer value.  Filters with lower values of the weight attribute will come before
40   * those with higher values within the same location.
41   *
42   * @since 2.1.0
43   */
44  public class ServletFilterModuleDescriptor extends BaseServletModuleDescriptor<Filter> implements StateAware
45  {
46      static final String DEFAULT_LOCATION = FilterLocation.BEFORE_DISPATCH.name();
47      static final String DEFAULT_WEIGHT = "100";
48  
49      private FilterLocation location;
50  
51      private int weight;
52      private final ServletModuleManager servletModuleManager;
53  
54      private Set<FilterDispatcherCondition> dispatcherConditions = Sets.newHashSet(FilterDispatcherCondition.REQUEST);
55  
56      /**
57       * Creates a descriptor that uses a module class factory to create instances.
58       *
59       * @param moduleFactory The module factory
60       * @param servletModuleManager The module manager
61       * @since 2.5.0
62       */
63      public ServletFilterModuleDescriptor(ModuleFactory moduleFactory, ServletModuleManager servletModuleManager)
64      {
65          super(moduleFactory);
66          this.servletModuleManager = checkNotNull(servletModuleManager);
67      }
68  
69      public static final Comparator<ServletFilterModuleDescriptor> byWeight = new Comparator<ServletFilterModuleDescriptor>()
70      {
71          public int compare(ServletFilterModuleDescriptor lhs, ServletFilterModuleDescriptor rhs)
72          {
73              return Integer.valueOf(lhs.getWeight()).compareTo(rhs.getWeight());
74          }
75      };
76  
77      @SuppressWarnings("unchecked")
78      public void init(Plugin plugin, Element element) throws PluginParseException
79      {
80          super.init(plugin, element);
81          try
82          {
83              location = FilterLocation.parse(element.attributeValue("location", DEFAULT_LOCATION));
84              weight = Integer.valueOf(element.attributeValue("weight", DEFAULT_WEIGHT));
85          }
86          catch (IllegalArgumentException ex)
87          {
88              throw new PluginParseException(ex);
89          }
90  
91          List<Element> dispatcherElements = element.elements("dispatcher");
92          if (!dispatcherElements.isEmpty()) {
93              dispatcherConditions.clear();
94              for (Element dispatcher : dispatcherElements)
95              {
96                  // already been validated via the validation rules
97                  dispatcherConditions.add(FilterDispatcherCondition.valueOf(dispatcher.getTextTrim()));
98              }
99          }
100     }
101 
102     @Override
103     protected void provideValidationRules(ValidationPattern pattern) {
104         super.provideValidationRules(pattern);
105         StringBuilder conditionRule = new StringBuilder();
106         conditionRule.append("dispatcher[");
107         for (int x = 0; x < FilterDispatcherCondition.values().length; x++)
108         {
109             conditionRule.append(". != '").append(FilterDispatcherCondition.values()[x]).append("'");
110             if (x + 1 < FilterDispatcherCondition.values().length)
111             {
112                 conditionRule.append(" and ");
113             }
114         }
115         conditionRule.append("]");
116         pattern.rule(conditionRule.toString(), test("dispatcher")
117                 .withError("The dispatcher value must be one of the following only " + Arrays.asList(FilterDispatcherCondition.values())));
118     }
119 
120     public void enabled()
121     {
122         super.enabled();
123         servletModuleManager.addFilterModule(this);
124     }
125 
126     public void disabled()
127     {
128         servletModuleManager.removeFilterModule(this);
129         super.disabled();
130     }
131 
132     @Override
133     public Filter getModule()
134     {
135         return moduleFactory.createModule(moduleClassName, this);
136     }
137 
138     public FilterLocation getLocation()
139     {
140         return location;
141     }
142 
143     public int getWeight()
144     {
145         return weight;
146     }
147 
148     /**
149      * Returns a set of dispatcher conditions that have been set for this filter, these conditions
150      * will be one of the following: <code>REQUEST, FORWARD, INCLUDE or ERROR</code>.
151      *
152      * @return A set of dispatcher conditions that have been set for this filter.
153      * @since 2.5.0
154      */
155     public Set<FilterDispatcherCondition> getDispatcherConditions()
156     {
157         return dispatcherConditions;
158     }
159 }