You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IsolatedLauncherProxy.java 3.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * SonarQube Runner - API
  3. * Copyright (C) 2011 SonarSource
  4. * sonarqube@googlegroups.com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
  19. */
  20. package org.sonar.runner.impl;
  21. import org.sonar.runner.cache.Logger;
  22. import java.lang.reflect.InvocationHandler;
  23. import java.lang.reflect.InvocationTargetException;
  24. import java.lang.reflect.Method;
  25. import java.lang.reflect.Proxy;
  26. import java.lang.reflect.UndeclaredThrowableException;
  27. public class IsolatedLauncherProxy implements InvocationHandler {
  28. private final Object proxied;
  29. private final ClassLoader cl;
  30. private final Logger logger;
  31. private IsolatedLauncherProxy(ClassLoader cl, Object proxied, Logger logger) {
  32. this.cl = cl;
  33. this.proxied = proxied;
  34. this.logger = logger;
  35. }
  36. public static <T> T create(ClassLoader cl, Class<T> interfaceClass, String proxiedClassName, Logger logger) throws ReflectiveOperationException {
  37. Object proxied = createProxiedObject(cl, proxiedClassName);
  38. // interfaceClass needs to be loaded with a parent ClassLoader (common to both ClassLoaders)
  39. // In addition, Proxy.newProxyInstance checks if the target ClassLoader sees the same class as the one given
  40. Class<?> loadedInterfaceClass = cl.loadClass(interfaceClass.getName());
  41. return (T) create(cl, proxied, loadedInterfaceClass, logger);
  42. }
  43. public static <T> T create(ClassLoader cl, Object proxied, Class<T> interfaceClass, Logger logger) {
  44. Class<?>[] c = {interfaceClass};
  45. return (T) Proxy.newProxyInstance(cl, c, new IsolatedLauncherProxy(cl, proxied, logger));
  46. }
  47. @Override
  48. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  49. ClassLoader initialContextClassLoader = Thread.currentThread().getContextClassLoader();
  50. try {
  51. Thread.currentThread().setContextClassLoader(cl);
  52. logger.debug("Execution " + method.getName());
  53. return method.invoke(proxied, args);
  54. } catch (UndeclaredThrowableException | InvocationTargetException e) {
  55. throw unwrapException(e);
  56. } finally {
  57. Thread.currentThread().setContextClassLoader(initialContextClassLoader);
  58. }
  59. }
  60. private static Throwable unwrapException(Throwable e) {
  61. Throwable cause = e;
  62. while (cause.getCause() != null) {
  63. if (cause instanceof UndeclaredThrowableException || cause instanceof InvocationTargetException) {
  64. cause = cause.getCause();
  65. } else {
  66. break;
  67. }
  68. }
  69. return cause;
  70. }
  71. private static Object createProxiedObject(ClassLoader cl, String proxiedClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
  72. Class<?> proxiedClass = cl.loadClass(proxiedClassName);
  73. return proxiedClass.newInstance();
  74. }
  75. }