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.beans.config.ContentRepository;
37 import info.magnolia.cms.core.Content;
38 import info.magnolia.content2bean.Content2BeanException;
39 import info.magnolia.content2bean.Content2BeanUtil;
40 import info.magnolia.module.InstallContext;
41 import info.magnolia.module.delta.AllChildrenNodesOperation;
42 import info.magnolia.module.delta.ArrayDelegateTask;
43 import info.magnolia.module.delta.TaskExecutionException;
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.", ContentRepository.CONFIG, existingFiltersPath);
86 this.subtasks = new ArrayDelegateTask("Filter updates");
87 this.existingFiltersPath = existingFiltersPath;
88
89
90 filterChain30.put(FILTER_CONTENT_TYPE,
91 new Filter30("info.magnolia.cms.filters.ContentTypeFilter",
92 new Long(100)));
93 filterChain30.put(FILTER_SECURITY,
94 new Filter30("info.magnolia.cms.security.SecurityFilter",
95 new Long(200)));
96 filterChain30.put(FILTER_VIRTUAL_URI,
97 new Filter30("info.magnolia.cms.filters.MgnlVirtualUriFilter",
98 new Long(300)));
99 filterChain30.put(FILTER_MULTIPART_REQUEST,
100 new Filter30("info.magnolia.cms.filters.MultipartRequestFilter",
101 new Long(400)));
102 filterChain30.put(FILTER_CONTEXT,
103 new Filter30("info.magnolia.cms.filters.MgnlContextFilter",
104 new Long(500)));
105 final HashMap interceptFilterParams = new HashMap();
106 interceptFilterParams.put("test", "true");
107 filterChain30.put(FILTER_INTERCEPT,
108 new Filter30("info.magnolia.cms.filters.MgnlInterceptFilter",
109 new Long(600),
110 null,
111 interceptFilterParams));
112 filterChain30.put(FILTER_CMS,
113 new Filter30("info.magnolia.cms.filters.MgnlCmsFilter",
114 new Long(800),
115 "/.,/docroot/,/admindocroot/,/tmp/fckeditor/,/ActivationHandler"));
116 }
117
118
119
120
121 public void execute(InstallContext installContext) throws TaskExecutionException {
122 super.execute(installContext);
123 subtasks.execute(installContext);
124 }
125
126 protected void operateOnChildNode(Content node, InstallContext ctx) throws RepositoryException,
127 TaskExecutionException {
128
129 try {
130 final Map existingFilter = Content2BeanUtil.toPureMaps(node, true);
131 final String currentFilter = node.getName();
132 final CheckAndUpdateExistingFilters.Filter30 originalFilter = (CheckAndUpdateExistingFilters.Filter30) filterChain30.get(currentFilter);
133
134 if (originalFilter == null ||
135 hasClassChanged(originalFilter, existingFilter) ||
136 hasPriorityChanged(originalFilter, existingFilter) ||
137 hasParamsChanged(originalFilter, existingFilter)) {
138 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.");
139 }
140
141 if (originalFilter != null && hasBypassChanged(originalFilter, existingFilter)) {
142 if (ArrayUtils.contains(migratedFilters, currentFilter)) {
143 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.");
144 migrateBypasses(existingFilter, currentFilter);
145 } else {
146 ctx.warn("Existing configuration of filter '" + currentFilter + "' has different bypass definitions. Magnolia put a backup in " + existingFiltersPath + "/" + currentFilter + ". Please review the changes manually.");
147 }
148 }
149 } catch (Content2BeanException e) {
150 ctx.error("Cannot convert filter node to map", e);
151 }
152 }
153
154 private void migrateBypasses(final Map existingFilter, final String newFilterName) {
155 final String filterPath = "/server/filters/" + newFilterName ;
156 final String existingBypassesList = getBypasses(existingFilter);
157 final String[] existingBypasses = StringUtils.split(existingBypassesList, ",");
158 for (int i = 0; i < existingBypasses.length; i++) {
159 final String bypassPattern = StringUtils.trim(existingBypasses[i]);
160 String bypassName = StringUtils.replaceChars(bypassPattern, "/* ", "");
161 if (bypassName.equals(".")) {
162 bypassName = "dot";
163 }
164 if (StringUtils.isEmpty(bypassName)) {
165 bypassName = "default";
166 }
167 final Class bypassClass = URIStartsWithVoter.class;
168
169 subtasks.addTask(new AddFilterBypassTask(filterPath, bypassName , bypassClass , bypassPattern));
170 }
171 }
172
173 private boolean hasClassChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
174 return !originalFilter.clazz.equals(existingFilter.get("class"));
175 }
176
177 private boolean hasBypassChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
178 final String bypasses = getBypasses(existingFilter);
179 return !originalFilter.equalBypasses(bypasses);
180 }
181
182 private String getBypasses(final Map existingFilter) {
183 String bypasses = null;
184 final Map existingConfig = (Map) existingFilter.get("config");
185 if (existingConfig != null && existingConfig.containsKey("bypass"))
186 bypasses = (String) existingConfig.get("bypass");
187 return bypasses;
188 }
189
190 private boolean hasParamsChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
191 final Map existingParameters = ((Map) existingFilter.get("params"));
192 return !originalFilter.equalParams(existingParameters);
193 }
194
195 private boolean hasPriorityChanged(final CheckAndUpdateExistingFilters.Filter30 originalFilter, final Map existingFilter) {
196 return !originalFilter.priority.equals(existingFilter.get("priority"));
197 }
198
199 private static final class Filter30 {
200 private String clazz;
201 private Long priority;
202 private String bypasses;
203 private Map params;
204
205 public Filter30(String clazz, Long priority) {
206 super();
207 this.clazz = clazz;
208 this.priority = priority;
209 }
210
211 public Filter30(String clazz, Long priority, String bypasses) {
212 super();
213 this.clazz = clazz;
214 this.priority = priority;
215 this.bypasses = bypasses;
216 }
217
218 public Filter30(String clazz, Long priority, String bypasses, Map params) {
219 super();
220 this.clazz = clazz;
221 this.priority = priority;
222 this.bypasses = bypasses;
223 this.params = params;
224 }
225
226
227
228
229
230
231 private boolean equalParams(final Map existingFilterParams) {
232 if (params == null && existingFilterParams == null)
233 return true;
234 if (params == null || existingFilterParams == null)
235 return false;
236 if (params.size() != existingFilterParams.size())
237 return false;
238
239 final Iterator paramIterator = params.keySet().iterator();
240 while (paramIterator.hasNext()) {
241 final String currentParam = (String) paramIterator.next();
242 if (!existingFilterParams.containsKey(currentParam) || !existingFilterParams.get(currentParam).equals(params.get(currentParam)))
243 return false;
244 }
245 return true;
246 }
247
248 private boolean equalBypasses(final String existingBypasses) {
249 if (bypasses != null) {
250 return bypasses.equals(existingBypasses);
251 } else {
252 return existingBypasses == null;
253 }
254 }
255 }
256 }