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.cms.filters;
35
36 import java.util.Collections;
37 import javax.inject.Inject;
38 import javax.inject.Singleton;
39 import javax.jcr.PathNotFoundException;
40 import javax.jcr.RepositoryException;
41 import javax.jcr.observation.EventIterator;
42 import javax.jcr.observation.EventListener;
43 import javax.servlet.FilterConfig;
44 import javax.servlet.ServletException;
45
46 import org.apache.commons.lang.StringUtils;
47
48 import info.magnolia.cms.core.Content;
49 import info.magnolia.cms.core.HierarchyManager;
50 import info.magnolia.cms.servlets.ClasspathSpool;
51 import info.magnolia.cms.util.ObservationUtil;
52 import info.magnolia.content2bean.Content2BeanException;
53 import info.magnolia.content2bean.Content2BeanUtil;
54 import info.magnolia.context.MgnlContext;
55 import info.magnolia.context.SystemContext;
56 import info.magnolia.module.ModuleManager;
57 import info.magnolia.repository.RepositoryConstants;
58
59
60
61
62
63
64
65
66 @Singleton
67 public class FilterManagerImpl implements FilterManager {
68
69 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FilterManagerImpl.class);
70
71 private final EventListener filtersEventListener = new EventListener() {
72 @Override
73 public void onEvent(EventIterator arg0) {
74 MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
75 @Override
76 public void doExec() {
77 resetRootFilter();
78 }
79 }, true);
80 }
81 };
82
83 private final ModuleManager moduleManager;
84 private final SystemContext systemContext;
85 private final MgnlFilterDispatcher filterDispatcher = new MgnlFilterDispatcher();
86 private final Object resetLock = new Object();
87 private FilterConfig filterConfig;
88
89 @Inject
90 public FilterManagerImpl(ModuleManager moduleManager, SystemContext systemContext) {
91 this.moduleManager = moduleManager;
92 this.systemContext = systemContext;
93 }
94
95 @Override
96 public void init(FilterConfig filterConfig) throws ServletException {
97
98 this.filterConfig = filterConfig;
99 MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
100 @Override
101 public void doExec() {
102 try {
103 MgnlFilter filter = createRootFilter();
104 initRootFilter(filter, FilterManagerImpl.this.filterConfig);
105 filterDispatcher.replaceTargetFilter(filter);
106 } catch (ServletException e) {
107 log.error("Error initializing filters", e);
108 return;
109 }
110 if (!isSystemUIMode()) {
111 startObservation();
112 }
113 }
114 }, true);
115 }
116
117 @Override
118 public void destroy() {
119 MgnlFilter filter = filterDispatcher.replaceTargetFilter(null);
120 destroyRootFilter(filter);
121 }
122
123 @Override
124 public MgnlFilterDispatcher getFilterDispatcher() {
125 return filterDispatcher;
126 }
127
128 @Override
129 public void startUsingConfiguredFilters() {
130 resetRootFilter();
131 startObservation();
132 }
133
134 protected void resetRootFilter() {
135 synchronized (resetLock) {
136
137 MgnlFilter newFilter;
138 try {
139 newFilter = createRootFilter();
140 initRootFilter(newFilter, filterConfig);
141 } catch (ServletException e) {
142 log.error("Error initializing filters", e);
143 return;
144 }
145
146 final MgnlFilter oldFilter = filterDispatcher.replaceTargetFilter(newFilter);
147
148
149 doInSystemContextAsync("FilterChainDisposerThread", new MgnlContext.VoidOp() {
150 @Override
151 public void doExec() {
152 destroyRootFilter(oldFilter);
153 }
154 }, true);
155 }
156 }
157
158 protected MgnlFilter createRootFilter() throws ServletException {
159 if (isSystemUIMode()) {
160 return createSystemUIFilter();
161 }
162 return createConfiguredFilters();
163 }
164
165 protected void initRootFilter(MgnlFilter rootFilter, FilterConfig filterConfig) throws ServletException {
166 log.info("Initializing filters");
167 rootFilter.init(filterConfig);
168
169 if (log.isDebugEnabled()) {
170 printFilters(rootFilter);
171 }
172 }
173
174 protected void destroyRootFilter(MgnlFilter rootFilter) {
175 if (rootFilter != null) {
176 rootFilter.destroy();
177 }
178 }
179
180 private MgnlFilter createConfiguredFilters() throws ServletException {
181 try {
182 final HierarchyManager hm = systemContext.getHierarchyManager(RepositoryConstants.CONFIG);
183 final Content node = hm.getContent(SERVER_FILTERS);
184 MgnlFilter filter = (MgnlFilter) Content2BeanUtil.toBean(node, true, MgnlFilter.class);
185 if (filter == null) {
186 throw new ServletException("Unable to create filter objects");
187 }
188 return filter;
189 } catch (PathNotFoundException e) {
190 throw new ServletException("No filters configured at " + SERVER_FILTERS);
191 } catch (RepositoryException e) {
192 throw new ServletException("Can't read filter definitions", e);
193 } catch (Content2BeanException e) {
194 throw new ServletException("Can't create filter objects", e);
195 }
196 }
197
198
199
200
201
202 protected MgnlFilter createSystemUIFilter() {
203 final CompositeFilter systemUIFilter = new CompositeFilter();
204 final ServletDispatchingFilter classpathSpoolFilter = new ServletDispatchingFilter();
205 classpathSpoolFilter.setName("resources");
206 classpathSpoolFilter.setServletName("ClasspathSpool Servlet");
207 classpathSpoolFilter.setServletClass(ClasspathSpool.class.getName());
208 classpathSpoolFilter.addMapping("/.resources/*");
209 classpathSpoolFilter.addMapping("/favicon.ico");
210 classpathSpoolFilter.setParameters(Collections.emptyMap());
211 classpathSpoolFilter.setEnabled(true);
212 systemUIFilter.addFilter(classpathSpoolFilter);
213
214 final InstallFilter installFilter = new InstallFilter(moduleManager, this);
215 installFilter.setName("install");
216 systemUIFilter.addFilter(installFilter);
217 return systemUIFilter;
218 }
219
220
221
222
223
224 protected boolean isSystemUIMode() {
225 return moduleManager.getStatus().needsUpdateOrInstall();
226 }
227
228 protected void startObservation() {
229 ObservationUtil.registerDeferredChangeListener(
230 RepositoryConstants.CONFIG,
231 SERVER_FILTERS,
232 filtersEventListener,
233 1000,
234 5000);
235 }
236
237 private void printFilters(MgnlFilter rootFilter) {
238 log.debug("Here is the root filter as configured:");
239 printFilter(0, rootFilter);
240 }
241
242 private void printFilter(int indentation, MgnlFilter filter) {
243 log.debug("{}{} ({})", new Object[]{StringUtils.repeat(" ", indentation), filter.getName(), filter.toString()});
244 if (filter instanceof CompositeFilter) {
245 for (MgnlFilter nestedFilter : ((CompositeFilter) filter).getFilters()) {
246 printFilter(indentation + 2, nestedFilter);
247 }
248 }
249 }
250
251 private <T, E extends Throwable> void doInSystemContextAsync(final String threadName, final MgnlContext.Op<T, E> op, final boolean releaseAfterExecution) {
252 new Thread() {
253 {
254 setName(threadName);
255 }
256 @Override
257 public void run() {
258 try {
259 MgnlContext.doInSystemContext(op, releaseAfterExecution);
260 } catch (Throwable e) {
261 log.error("Exception caught when executing asynchronous operation: " + e.getMessage(), e);
262 }
263 }
264 }.start();
265 }
266 }