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