PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jruby-1.7.3/src/org/jruby/util/JRubyClassLoader.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 241 lines | 193 code | 33 blank | 15 comment | 31 complexity | be01ad2ff9b028adf01d14bc78651501 MD5 | raw file
  1. package org.jruby.util;
  2. import org.jruby.util.log.Logger;
  3. import org.jruby.util.log.LoggerFactory;
  4. import java.io.ByteArrayOutputStream;
  5. import java.io.Closeable;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.net.URL;
  9. import java.net.URLClassLoader;
  10. import java.security.ProtectionDomain;
  11. import java.util.ArrayList;
  12. import java.util.Enumeration;
  13. import java.util.HashSet;
  14. import java.util.Iterator;
  15. import java.util.LinkedHashMap;
  16. import java.util.List;
  17. import java.util.Map;
  18. import java.util.Set;
  19. import java.util.jar.JarEntry;
  20. import java.util.jar.JarInputStream;
  21. public class JRubyClassLoader extends URLClassLoader implements ClassDefiningClassLoader {
  22. private static final Logger LOG = LoggerFactory.getLogger("JRubyClassLoader");
  23. private final static ProtectionDomain DEFAULT_DOMAIN
  24. = JRubyClassLoader.class.getProtectionDomain();
  25. private final Map<URL,Set<String>> jarIndexes = new LinkedHashMap<URL,Set<String>>();
  26. private Runnable unloader;
  27. public JRubyClassLoader(ClassLoader parent) {
  28. super(new URL[0], parent);
  29. }
  30. // Change visibility so others can see it
  31. @Override
  32. public void addURL(URL url) {
  33. super.addURL(url);
  34. indexJarContents(url);
  35. }
  36. /**
  37. * Called when the parent runtime is torn down.
  38. */
  39. public void tearDown(boolean debug) {
  40. try {
  41. // A hack to allow unloading all JDBC Drivers loaded by this classloader.
  42. // See http://bugs.jruby.org/4226
  43. getJDBCDriverUnloader().run();
  44. } catch (Exception e) {
  45. if (debug) {
  46. LOG.debug(e);
  47. }
  48. }
  49. }
  50. public synchronized Runnable getJDBCDriverUnloader() {
  51. if (unloader == null) {
  52. try {
  53. InputStream unloaderStream = getClass().getResourceAsStream("/org/jruby/util/JDBCDriverUnloader.class");
  54. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  55. byte[] buf = new byte[4096];
  56. int bytesRead;
  57. while ((bytesRead = unloaderStream.read(buf)) != -1) {
  58. baos.write(buf, 0, bytesRead);
  59. }
  60. Class unloaderClass = defineClass("org.jruby.util.JDBCDriverUnloader", baos.toByteArray());
  61. unloader = (Runnable) unloaderClass.newInstance();
  62. } catch (Exception e) {
  63. throw new RuntimeException(e);
  64. }
  65. }
  66. return unloader;
  67. }
  68. public Class<?> defineClass(String name, byte[] bytes) {
  69. return super.defineClass(name, bytes, 0, bytes.length, DEFAULT_DOMAIN);
  70. }
  71. public Class<?> defineClass(String name, byte[] bytes, ProtectionDomain domain) {
  72. return super.defineClass(name, bytes, 0, bytes.length, domain);
  73. }
  74. @Override
  75. protected Class<?> findClass(String className) throws ClassNotFoundException {
  76. try {
  77. return super.findClass(className);
  78. } catch (ClassNotFoundException ex) {
  79. String resourceName = className.replace('.', '/').concat(".class");
  80. URL classUrl = null;
  81. synchronized (jarIndexes) {
  82. for (URL jarUrl : jarIndexes.keySet()) {
  83. if (jarIndexes.get(jarUrl).contains(resourceName)) {
  84. try {
  85. classUrl = CompoundJarURLStreamHandler.createUrl(jarUrl, resourceName);
  86. break;
  87. } catch (IOException e) {
  88. // keep going to next URL
  89. }
  90. }
  91. }
  92. }
  93. if (classUrl != null) {
  94. try {
  95. InputStream input = classUrl.openStream();
  96. try {
  97. byte[] buffer = new byte[4096];
  98. ByteArrayOutputStream output = new ByteArrayOutputStream();
  99. for (int count = input.read(buffer); count > 0; count = input.read(buffer)) {
  100. output.write(buffer, 0, count);
  101. }
  102. byte[] data = output.toByteArray();
  103. return defineClass(className, data, 0, data.length);
  104. } finally {
  105. close(input);
  106. }
  107. } catch (IOException e) {
  108. // just fall-through to the re-throw below
  109. }
  110. }
  111. throw ex;
  112. }
  113. }
  114. @Override
  115. public URL findResource(String resourceName) {
  116. URL result = super.findResource(resourceName);
  117. if (result == null) {
  118. synchronized (jarIndexes) {
  119. for (URL jarUrl : jarIndexes.keySet()) {
  120. if (jarIndexes.get(jarUrl).contains(resourceName)) {
  121. try {
  122. return CompoundJarURLStreamHandler.createUrl(jarUrl, resourceName);
  123. } catch (IOException e) {
  124. // keep going
  125. }
  126. }
  127. }
  128. }
  129. }
  130. return result;
  131. }
  132. @Override
  133. public Enumeration<URL> findResources(String resourceName) throws IOException {
  134. final List<URL> embeddedUrls = new ArrayList<URL>();
  135. synchronized (jarIndexes) {
  136. for (URL jarUrl : jarIndexes.keySet()) {
  137. if (jarIndexes.get(jarUrl).contains(resourceName)) {
  138. try {
  139. embeddedUrls.add(CompoundJarURLStreamHandler.createUrl(jarUrl, resourceName));
  140. } catch (IOException e) {
  141. // keep going
  142. }
  143. }
  144. }
  145. }
  146. if (embeddedUrls.isEmpty()) {
  147. return super.findResources(resourceName);
  148. } else {
  149. final Enumeration<URL> originalResult = super.findResources(resourceName);
  150. return new Enumeration<URL>() {
  151. private Iterator<URL> extendedResult;
  152. public URL nextElement() {
  153. if (extendedResult == null) {
  154. return originalResult.nextElement();
  155. } else {
  156. return extendedResult.next();
  157. }
  158. }
  159. public boolean hasMoreElements() {
  160. if (extendedResult == null) {
  161. boolean result = originalResult.hasMoreElements();
  162. if (!result) {
  163. // original result is consumed, switching to result
  164. // from embedded jars processing.
  165. extendedResult = embeddedUrls.iterator();
  166. result = extendedResult.hasNext();
  167. }
  168. return result;
  169. } else {
  170. return extendedResult.hasNext();
  171. }
  172. }
  173. };
  174. }
  175. }
  176. private void indexJarContents(URL jarUrl) {
  177. String proto = jarUrl.getProtocol();
  178. // we only need to index jar: and compoundjar: URLs
  179. // 1st-level jar files with file: URLs are handled by the JDK
  180. if (proto.equals("jar") || proto.equals(CompoundJarURLStreamHandler.PROTOCOL)) {
  181. synchronized (jarIndexes) {
  182. Set<String> entries = new HashSet<String>();
  183. jarIndexes.put(jarUrl, entries);
  184. try {
  185. InputStream baseInputStream = jarUrl.openStream();
  186. try {
  187. JarInputStream baseJar = new JarInputStream(baseInputStream);
  188. for (JarEntry entry = baseJar.getNextJarEntry(); entry != null; entry = baseJar.getNextJarEntry()) {
  189. entries.add(entry.getName());
  190. }
  191. } finally {
  192. close(baseInputStream);
  193. }
  194. } catch (IOException ex) {
  195. // can't read the stream, keep going
  196. }
  197. }
  198. }
  199. }
  200. private static void close(Closeable resource) {
  201. if (resource != null) {
  202. try {
  203. resource.close();
  204. } catch (IOException ignore) {
  205. }
  206. }
  207. }
  208. }