001
014
015 package com.liferay.portal.test.rule;
016
017 import com.liferay.portal.deploy.hot.HookHotDeployListener;
018 import com.liferay.portal.deploy.hot.IndexerPostProcessorRegistry;
019 import com.liferay.portal.deploy.hot.ServiceWrapperRegistry;
020 import com.liferay.portal.kernel.deploy.hot.DependencyManagementThreadLocal;
021 import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
022 import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
023 import com.liferay.portal.kernel.portlet.PortletClassLoaderUtil;
024 import com.liferay.portal.kernel.servlet.ServletContextPool;
025 import com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterHelper;
026 import com.liferay.portal.kernel.template.TemplateManagerUtil;
027 import com.liferay.portal.kernel.util.ClassLoaderPool;
028 import com.liferay.portal.kernel.util.ListUtil;
029 import com.liferay.portal.kernel.util.PortalLifecycleUtil;
030 import com.liferay.portal.kernel.util.PropsKeys;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.service.test.ServiceTestUtil;
033 import com.liferay.portal.spring.context.PortletContextLoaderListener;
034 import com.liferay.portal.test.mock.AutoDeployMockServletContext;
035 import com.liferay.portal.util.InitUtil;
036 import com.liferay.portal.util.PortalUtil;
037 import com.liferay.portal.util.PropsUtil;
038
039 import java.lang.reflect.Method;
040
041 import java.net.MalformedURLException;
042 import java.net.URL;
043 import java.net.URLClassLoader;
044
045 import java.security.CodeSource;
046 import java.security.ProtectionDomain;
047
048 import java.util.List;
049 import java.util.Map;
050 import java.util.concurrent.ConcurrentHashMap;
051
052 import javax.servlet.ServletContext;
053 import javax.servlet.ServletContextEvent;
054
055 import org.junit.rules.TestRule;
056 import org.junit.runner.Description;
057 import org.junit.runners.model.Statement;
058
059 import org.springframework.core.io.ClassPathResource;
060 import org.springframework.core.io.FileSystemResourceLoader;
061 import org.springframework.core.io.Resource;
062 import org.springframework.core.io.ResourceLoader;
063 import org.springframework.mock.web.MockServletContext;
064
065
069 public class PACLTestRule implements TestRule {
070
071 public static final String RESOURCE_PATH =
072 "com/liferay/portal/security/pacl/test/dependencies";
073
074 @Override
075 public Statement apply(
076 final Statement statement, final Description description) {
077
078 return new Statement() {
079
080 @Override
081 public void evaluate() throws Throwable {
082 PortletContextLoaderListener portletContextLoaderListener =
083 new PortletContextLoaderListener();
084
085 HotDeployEvent hotDeployEvent = null;
086
087 if (description.getMethodName() != null) {
088 hotDeployEvent = beforeClass(
089 description, portletContextLoaderListener);
090 }
091
092 try {
093 invokeStatement(statement, description);
094 }
095 finally {
096 if (hotDeployEvent != null) {
097 afterClass(
098 description, hotDeployEvent,
099 portletContextLoaderListener);
100 }
101 }
102 }
103
104 };
105 }
106
107 protected void afterClass(
108 Description description, HotDeployEvent hotDeployEvent,
109 PortletContextLoaderListener portletContextLoaderListener) {
110
111 HotDeployUtil.fireUndeployEvent(hotDeployEvent);
112
113 ClassLoaderPool.register(
114 hotDeployEvent.getServletContextName(),
115 hotDeployEvent.getContextClassLoader());
116 PortletClassLoaderUtil.setServletContextName(
117 hotDeployEvent.getServletContextName());
118
119 try {
120 portletContextLoaderListener.contextDestroyed(
121 new ServletContextEvent(hotDeployEvent.getServletContext()));
122 }
123 finally {
124 ClassLoaderPool.unregister(hotDeployEvent.getServletContextName());
125 PortletClassLoaderUtil.setServletContextName(null);
126 }
127 }
128
129 protected HotDeployEvent beforeClass(
130 Description description,
131 PortletContextLoaderListener portletContextLoaderListener)
132 throws ReflectiveOperationException {
133
134 _testClass = _loadTestClass(description.getTestClass());
135 _instance = _testClass.newInstance();
136
137 ServletContext servletContext = ServletContextPool.get(
138 PortalUtil.getServletContextName());
139
140 if (servletContext == null) {
141 servletContext = new AutoDeployMockServletContext(
142 new FileSystemResourceLoader());
143
144 servletContext.setAttribute(
145 InvokerFilterHelper.class.getName(), new InvokerFilterHelper());
146
147 ServletContextPool.put(PortalUtil.getPathContext(), servletContext);
148 }
149
150 HotDeployUtil.reset();
151
152 HotDeployUtil.registerListener(new HookHotDeployListener());
153
154 HotDeployUtil.setCapturePrematureEvents(false);
155
156 PortalLifecycleUtil.flushInits();
157
158 ClassLoader classLoader = _testClass.getClassLoader();
159
160 MockServletContext mockServletContext = new MockServletContext(
161 new PACLResourceLoader(classLoader));
162
163 mockServletContext.setServletContextName("a-test-hook");
164
165 HotDeployEvent hotDeployEvent = getHotDeployEvent(
166 mockServletContext, classLoader);
167
168 HotDeployUtil.fireDeployEvent(hotDeployEvent);
169
170 ClassLoaderPool.register(
171 hotDeployEvent.getServletContextName(),
172 hotDeployEvent.getContextClassLoader());
173 PortletClassLoaderUtil.setServletContextName(
174 hotDeployEvent.getServletContextName());
175
176 try {
177 portletContextLoaderListener.contextInitialized(
178 new ServletContextEvent(mockServletContext));
179 }
180 finally {
181 ClassLoaderPool.unregister(hotDeployEvent.getServletContextName());
182 PortletClassLoaderUtil.setServletContextName(null);
183 }
184
185 return hotDeployEvent;
186 }
187
188 protected HotDeployEvent getHotDeployEvent(
189 ServletContext servletContext, ClassLoader classLoader) {
190
191 boolean dependencyManagementEnabled =
192 DependencyManagementThreadLocal.isEnabled();
193
194 try {
195 DependencyManagementThreadLocal.setEnabled(false);
196
197 return new HotDeployEvent(servletContext, classLoader);
198 }
199 finally {
200 DependencyManagementThreadLocal.setEnabled(
201 dependencyManagementEnabled);
202 }
203 }
204
205 protected void invokeStatement(Statement statement, Description description)
206 throws Throwable {
207
208 String methodName = description.getMethodName();
209
210 if (methodName == null) {
211 statement.evaluate();
212
213 return;
214 }
215
216 Method method = _testClass.getMethod(description.getMethodName());
217
218 method.invoke(_instance);
219 }
220
221 private static Class<?> _loadTestClass(Class<?> clazz)
222 throws ClassNotFoundException {
223
224 ProtectionDomain protectionDomain = clazz.getProtectionDomain();
225
226 CodeSource codeSource = protectionDomain.getCodeSource();
227
228 ClassLoader classLoader = new PACLClassLoader(
229 new URL[] {codeSource.getLocation()}, clazz.getClassLoader());
230
231 return Class.forName(clazz.getName(), true, classLoader);
232 }
233
234 private static final String _PACKAGE_PATH =
235 "com.liferay.portal.security.pacl.test.";
236
237 static {
238 List<String> configLocations = ListUtil.fromArray(
239 PropsUtil.getArray(PropsKeys.SPRING_CONFIGS));
240
241 InitUtil.initWithSpring(configLocations, true);
242
243 ServiceTestUtil.initMainServletServices();
244 ServiceTestUtil.initStaticServices();
245 ServiceTestUtil.initServices();
246 ServiceTestUtil.initPermissions();
247
248 new IndexerPostProcessorRegistry();
249 new ServiceWrapperRegistry();
250
251 try {
252 Class.forName(
253 TemplateManagerUtil.class.getName(), true,
254 PACLTestRule.class.getClassLoader());
255 }
256 catch (ClassNotFoundException cnfe) {
257 throw new ExceptionInInitializerError(cnfe);
258 }
259 }
260
261 private Object _instance;
262 private Class<?> _testClass;
263
264 private static class PACLClassLoader extends URLClassLoader {
265
266 public PACLClassLoader(URL[] urls, ClassLoader parentClassLoader) {
267 super(urls, parentClassLoader);
268 }
269
270 @Override
271 public URL findResource(String name) {
272 if (_urls.containsKey(name)) {
273 return _urls.get(name);
274 }
275
276 URL resource = null;
277
278 if (!name.contains(RESOURCE_PATH)) {
279 String newName = name;
280
281 if (!newName.startsWith(StringPool.SLASH)) {
282 newName = StringPool.SLASH.concat(newName);
283 }
284
285 newName = RESOURCE_PATH.concat(newName);
286
287 resource = super.findResource(newName);
288 }
289
290 if ((resource == null) && !name.contains(RESOURCE_PATH)) {
291 String newName = name;
292
293 if (!newName.startsWith(StringPool.SLASH)) {
294 newName = StringPool.SLASH.concat(newName);
295 }
296
297 newName = RESOURCE_PATH.concat("/WEB-INF/classes").concat(
298 newName);
299
300 resource = super.findResource(newName);
301 }
302
303 if (resource == null) {
304 resource = super.findResource(name);
305 }
306
307 if (resource != null) {
308 _urls.put(name, resource);
309 }
310
311 return resource;
312 }
313
314 @Override
315 public URL getResource(String name) {
316 if (name.equals(
317 "com/liferay/util/bean/PortletBeanLocatorUtil.class")) {
318
319 URL url = findResource("/");
320
321 String path = url.getPath();
322
323 path = path.substring(
324 0, path.length() - RESOURCE_PATH.length() - 1);
325
326 path = path.concat(name);
327
328 try {
329 return new URL("file", null, path);
330 }
331 catch (MalformedURLException murle) {
332 }
333 }
334
335 URL url = findResource(name);
336
337 if (url != null) {
338 return url;
339 }
340
341 return super.getResource(name);
342 }
343
344 @Override
345 public Class<?> loadClass(String name) throws ClassNotFoundException {
346 if (name.startsWith(_PACKAGE_PATH)) {
347 if (_classes.containsKey(name)) {
348 return _classes.get(name);
349 }
350
351 Class<?> clazz = super.findClass(name);
352
353 _classes.put(name, clazz);
354
355 return clazz;
356 }
357
358 return super.loadClass(name);
359 }
360
361 @Override
362 protected synchronized Class<?> loadClass(String name, boolean resolve)
363 throws ClassNotFoundException {
364
365 if (name.startsWith(_PACKAGE_PATH)) {
366 if (_classes.containsKey(name)) {
367 return _classes.get(name);
368 }
369
370 Class<?> clazz = super.findClass(name);
371
372 _classes.put(name, clazz);
373
374 return clazz;
375 }
376
377 return super.loadClass(name, resolve);
378 }
379
380 private final Map<String, Class<?>> _classes =
381 new ConcurrentHashMap<>();
382 private final Map<String, URL> _urls = new ConcurrentHashMap<>();
383
384 }
385
386 private static class PACLResourceLoader implements ResourceLoader {
387
388 public PACLResourceLoader(ClassLoader classLoader) {
389 _classLoader = classLoader;
390 }
391
392 @Override
393 public ClassLoader getClassLoader() {
394 return _classLoader;
395 }
396
397 @Override
398 public Resource getResource(String location) {
399 ClassLoader classLoader = getClassLoader();
400
401 return new ClassPathResource(RESOURCE_PATH + location, classLoader);
402 }
403
404 private final ClassLoader _classLoader;
405
406 }
407
408 }