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.annotations.VisibleForTesting;
12 import io.atlassian.util.concurrent.ResettableLazyReference;
13 import org.dom4j.Element;
14
15 import javax.servlet.DispatcherType;
16 import javax.servlet.Filter;
17 import java.util.Arrays;
18 import java.util.Comparator;
19 import java.util.EnumSet;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.Set;
23
24 import static com.atlassian.plugin.util.validation.ValidationPattern.test;
25 import static com.google.common.base.Preconditions.checkNotNull;
26 import static java.util.stream.Collectors.toSet;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class ServletFilterModuleDescriptor extends BaseServletModuleDescriptor<Filter> implements StateAware {
49
50
51
52
53 @VisibleForTesting
54 static final String FORCE_ASYNC_DISPATCHER_SYSPROP = "atlassian.plugins.filter.force.async.dispatcher";
55 @VisibleForTesting
56 static final ResettableLazyReference<Boolean> FORCE_ASYNC = new ResettableLazyReference<Boolean>() {
57 @Override
58 protected Boolean create() {
59 return Boolean.getBoolean(FORCE_ASYNC_DISPATCHER_SYSPROP);
60 }
61 };
62
63 static final String DEFAULT_LOCATION = FilterLocation.BEFORE_DISPATCH.name();
64 static final String DEFAULT_WEIGHT = "100";
65
66 private FilterLocation location;
67
68 private int weight;
69 private final ServletModuleManager servletModuleManager;
70
71 private Set<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
72
73
74
75
76
77
78
79
80 public ServletFilterModuleDescriptor(ModuleFactory moduleFactory, ServletModuleManager servletModuleManager) {
81 super(moduleFactory);
82 this.servletModuleManager = checkNotNull(servletModuleManager);
83 }
84
85 public static final Comparator<ServletFilterModuleDescriptor> byWeight =
86 Comparator.comparingInt(ServletFilterModuleDescriptor::getWeight);
87
88 @SuppressWarnings("unchecked")
89 public void init(Plugin plugin, Element element) throws PluginParseException {
90 super.init(plugin, element);
91 try {
92 location = FilterLocation.parse(element.attributeValue("location", DEFAULT_LOCATION));
93 weight = Integer.valueOf(element.attributeValue("weight", DEFAULT_WEIGHT));
94 } catch (IllegalArgumentException ex) {
95 throw new PluginParseException(ex);
96 }
97
98 List<Element> dispatcherElements = element.elements("dispatcher");
99 if (!dispatcherElements.isEmpty()) {
100 dispatcherTypes.clear();
101 for (Element dispatcher : dispatcherElements) {
102
103 dispatcherTypes.add(DispatcherType.valueOf(dispatcher.getTextTrim()));
104 }
105 }
106 if (FORCE_ASYNC.get()) {
107 dispatcherTypes.add(DispatcherType.ASYNC);
108 }
109 }
110
111 @Override
112 protected void provideValidationRules(ValidationPattern pattern) {
113 super.provideValidationRules(pattern);
114 StringBuilder conditionRule = new StringBuilder();
115 conditionRule.append("dispatcher[");
116 DispatcherType[] dispatcherTypes = DispatcherType.values();
117 for (int x = 0; x < dispatcherTypes.length; x++) {
118 conditionRule.append(". != '").append(dispatcherTypes[x]).append("'");
119 if (x + 1 < dispatcherTypes.length) {
120 conditionRule.append(" and ");
121 }
122 }
123 conditionRule.append("]");
124 pattern.rule(conditionRule.toString(),
125 test("dispatcher").withError("The dispatcher value must be one of the following only " + Arrays.asList(DispatcherType.values())),
126 test("@class").withError("The class is required"));
127 }
128
129 public void enabled() {
130 super.enabled();
131 servletModuleManager.addFilterModule(this);
132 }
133
134 public void disabled() {
135 servletModuleManager.removeFilterModule(this);
136 super.disabled();
137 }
138
139 @Override
140 public Filter getModule() {
141 return moduleFactory.createModule(moduleClassName, this);
142 }
143
144 public FilterLocation getLocation() {
145 return location;
146 }
147
148 public int getWeight() {
149 return weight;
150 }
151
152
153
154
155
156
157
158
159
160 public Set<FilterDispatcherCondition> getDispatcherConditions() {
161 return dispatcherTypes.stream()
162 .map(FilterDispatcherCondition::fromDispatcherType)
163 .filter(Objects::nonNull)
164 .collect(toSet());
165 }
166
167
168
169
170
171
172
173
174 public Set<DispatcherType> getDispatcherTypes() {
175 return dispatcherTypes;
176 }
177 }