1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.setup.for3_5;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.content2bean.Content2BeanException;
38 import info.magnolia.content2bean.Content2BeanUtil;
39 import info.magnolia.module.InstallContext;
40 import info.magnolia.module.delta.AllChildrenNodesOperation;
41 import info.magnolia.module.delta.ArrayDelegateTask;
42 import info.magnolia.module.delta.TaskExecutionException;
43 import info.magnolia.repository.RepositoryConstants;
44 import info.magnolia.setup.AddFilterBypassTask;
45 import info.magnolia.voting.voters.URIStartsWithVoter;
46
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.LinkedHashMap;
50 import java.util.Map;
51
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang.ArrayUtils;
55 import org.apache.commons.lang.StringUtils;
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public final class CheckAndUpdateExistingFilters extends AllChildrenNodesOperation {
70 private static final String FILTER_INTERCEPT = "intercept";
71 private static final String FILTER_SECURITY = "security";
72 private static final String FILTER_CMS = "cms";
73 private static final String FILTER_CONTEXT = "context";
74 private static final String FILTER_MULTIPART_REQUEST = "multipartRequest";
75 private static final String FILTER_VIRTUAL_URI = "virtualURI";
76 private static final String FILTER_CONTENT_TYPE = "contentType";
77
78 private final LinkedHashMap filterChain30 = new LinkedHashMap();
79 private final String existingFiltersPath;
80 private final String[] migratedFilters = new String[] { FILTER_CONTENT_TYPE, FILTER_VIRTUAL_URI, FILTER_MULTIPART_REQUEST, FILTER_CONTEXT, FILTER_CMS };
81
82 private final ArrayDelegateTask subtasks;
83
84 public CheckAndUpdateExistingFilters(String existingFiltersPath) {
85 super("Filters", "Installs or updates the new filter configuration.", RepositoryConstants.CONFIG,
86 existingFiltersPath);
87 this.subtasks = new ArrayDelegateTask("Filter updates");
88 this.existingFiltersPath = existingFiltersPath;
89
90
91 filterChain30.put(FILTER_CONTENT_TYPE,
92 new Filter30("info.magnolia.cms.filters.ContentTypeFilter", Long.valueOf(100)));
93 filterChain30
94 .put(FILTER_SECURITY, new Filter30("info.magnolia.cms.security.SecurityFilter", Long.valueOf(200)));
95 filterChain30.put(FILTER_VIRTUAL_URI,
96 new Filter30("info.magnolia.cms.filters.MgnlVirtualUriFilter", Long.valueOf(300)));
97 filterChain30.put(FILTER_MULTIPART_REQUEST, new Filter30("info.magnolia.cms.filters.MultipartRequestFilter",
98 Long.valueOf(400)));
99 filterChain30.put(FILTER_CONTEXT,
100 new Filter30("info.magnolia.cms.filters.MgnlContextFilter", Long.valueOf(500)));
101 final HashMap interceptFilterParams = new HashMap();
102 interceptFilterParams.put("test", "true");
103 filterChain30.put(FILTER_INTERCEPT,
104 new Filter30("info.magnolia.cms.filters.MgnlInterceptFilter", Long.valueOf(600), null,
105 interceptFilterParams));
106 filterChain30.put(FILTER_CMS, new Filter30("info.magnolia.cms.filters.MgnlCmsFilter", Long.valueOf(800),
107 "/.,/docroot/,/admindocroot/,/tmp/fckeditor/,/ActivationHandler"));
108 }
109
110
111
112
113 @Override
114 public void execute(InstallContext installContext) throws TaskExecutionException {
115 super.execute(installContext);
116 subtasks.execute(installContext);
117 }
118
119 @Override
120 protected void operateOnChildNode(Content node, InstallContext ctx) throws RepositoryException,
121 TaskExecutionException {
122
123 try {
124 final Map existingFilter = Content2BeanUtil.toPureMaps(node, true);
125 final String currentFilter = node.getName();
126 final CheckAndUpdateExistingFilters.Filter30 originalFilter = (CheckAndUpdateExistingFilters.Filter30) filterChain30.get(currentFilter);
127
128 if (originalFilter == null || hasClassChanged(originalFilter, existingFilter)
129 || hasPriorityChanged(originalFilter, existingFilter)
130 ||
131 hasParamsChanged(originalFilter, existingFilter)) {
132 ctx.warn("Existing configuration of filter '" + currentFilter + "' has been modified or was not existing in original filter chain. Magnolia put a backup in " + existingFiltersPath + "/" + currentFilter + ". Please review the changes manually.");
133 }
134
135 if (originalFilter != null && hasBypassChanged(originalFilter, existingFilter)) {
136 if (ArrayUtils.contains(migratedFilters, currentFilter)) {
137 ctx.info("Existing configuration of filter '" + currentFilter + "' has different bypass definitions. Magnolia put a backup in " + existingFiltersPath + "/" + currentFilter + ". Will update the bypasses to the new configuration automatically.");
138 migrateBypasses(existingFilter, currentFilter);
139 } else {
140 ctx.warn("Existing configuration of filter '" + currentFilter + "' has different bypass definitions. Magnolia put a backup in " + existingFiltersPath + "/" + currentFilter + ". Please review the changes manually.");
141 }
142 }
143 } catch (Content2BeanException e) {
144 ctx.error("Cannot convert filter node to map", e);
145 }
146 }
147
148 private void migrateBypasses(final Map existingFilter, final String newFilterName) {
149 final String filterPath = "/server/filters/" + newFilterName ;
150 final String existingBypassesList = getBypasses(existingFilter);
151 final String[] existingBypasses = StringUtils.split(existingBypassesList, ",");
152 for (int i = 0; i < existingBypasses.length; i++) {
153 final String bypassPattern = StringUtils.trim(existingBypasses[i]);
154 String bypassName = StringUtils.replaceChars(bypassPattern, "/* ", "");
155 if (bypassName.equals(".")) {
156 bypassName = "dot";
157 }
158 if (StringUtils.isEmpty(bypassName)) {
159 bypassName = "default";
160 }
161 final Class bypassClass = URIStartsWithVoter.class;
162
163 subtasks.addTask(new AddFilterBypassTask(filterPath, bypassName , bypassClass , bypassPattern));
164 }
165 }
166
167 private boolean hasClassChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
168 return !originalFilter.clazz.equals(existingFilter.get("class"));
169 }
170
171 private boolean hasBypassChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
172 final String bypasses = getBypasses(existingFilter);
173 return !originalFilter.equalBypasses(bypasses);
174 }
175
176 private String getBypasses(final Map existingFilter) {
177 String bypasses = null;
178 final Map existingConfig = (Map) existingFilter.get("config");
179 if (existingConfig != null && existingConfig.containsKey("bypass")) {
180 bypasses = (String) existingConfig.get("bypass");
181 }
182 return bypasses;
183 }
184
185 private boolean hasParamsChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
186 final Map existingParameters = ((Map) existingFilter.get("params"));
187 return !originalFilter.equalParams(existingParameters);
188 }
189
190 private boolean hasPriorityChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
191 return !originalFilter.priority.equals(existingFilter.get("priority"));
192 }
193
194 private static final class Filter30 {
195 private String clazz;
196 private Long priority;
197 private String bypasses;
198 private Map params;
199
200 public Filter30(String clazz, Long priority) {
201 super();
202 this.clazz = clazz;
203 this.priority = priority;
204 }
205
206 public Filter30(String clazz, Long priority, String bypasses) {
207 super();
208 this.clazz = clazz;
209 this.priority = priority;
210 this.bypasses = bypasses;
211 }
212
213 public Filter30(String clazz, Long priority, String bypasses, Map params) {
214 super();
215 this.clazz = clazz;
216 this.priority = priority;
217 this.bypasses = bypasses;
218 this.params = params;
219 }
220
221
222
223
224
225
226 private boolean equalParams(final Map existingFilterParams) {
227 if (params == null && existingFilterParams == null) {
228 return true;
229 }
230 if (params == null || existingFilterParams == null) {
231 return false;
232 }
233 if (params.size() != existingFilterParams.size()) {
234 return false;
235 }
236
237 final Iterator paramIterator = params.keySet().iterator();
238 while (paramIterator.hasNext()) {
239 final String currentParam = (String) paramIterator.next();
240 if (!existingFilterParams.containsKey(currentParam) || !existingFilterParams.get(currentParam).equals(params.get(currentParam))) {
241 return false;
242 }
243 }
244 return true;
245 }
246
247 private boolean equalBypasses(final String existingBypasses) {
248 if (bypasses != null) {
249 return bypasses.equals(existingBypasses);
250 }
251 return existingBypasses == null;
252 }
253 }
254 }