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