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