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