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