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.

GlobalClassLoader.java 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2006-2017 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  5. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to the following conditions:
  8. *
  9. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
  10. * Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  14. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  15. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. */
  17. package com.dmdirc.plugins;
  18. import com.dmdirc.util.resourcemanager.ResourceManager;
  19. import java.io.IOException;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import javax.annotation.Nullable;
  24. /**
  25. * This classloader knows about plugins and is used to store persistent classes.
  26. */
  27. public final class GlobalClassLoader extends ClassLoader {
  28. /** HashMap containing sources of Global class files. */
  29. private final Map<String, String> resourcesList = new HashMap<>();
  30. /** Plugin Manager that owns this GlobalClassLoader. */
  31. private final PluginManager manager;
  32. /**
  33. * Create a new GlobalClassLoader.
  34. *
  35. * @param manager Plugin Manager that this GCL is used by.
  36. */
  37. public GlobalClassLoader(final PluginManager manager) {
  38. this.manager = manager;
  39. }
  40. /**
  41. * Have we already loaded the given class name?
  42. *
  43. * @param name Name to check.
  44. *
  45. * @return True if the class is loaded, false otherwise
  46. */
  47. public boolean isClassLoaded(final String name) {
  48. return findLoadedClass(name) != null;
  49. }
  50. /**
  51. * Load the plugin with the given className.
  52. *
  53. * @param name Class Name of plugin
  54. * @param pi The PluginInfo that contains this class
  55. *
  56. * @return plugin class
  57. *
  58. * @throws ClassNotFoundException if the class to be loaded could not be found.
  59. */
  60. public Class<?> loadClass(final String name, final PluginInfo pi) throws ClassNotFoundException {
  61. pi.getPersistentClasses().stream()
  62. .filter(classname -> !resourcesList.containsKey(classname))
  63. .forEach(classname -> resourcesList.put(classname,
  64. pi.getMetaData().getPluginPath().toAbsolutePath().toString()));
  65. return loadClass(name);
  66. }
  67. @Override
  68. public Class<?> loadClass(final String name) throws ClassNotFoundException {
  69. try {
  70. return super.loadClass(name);
  71. } catch (ClassNotFoundException e) {
  72. final byte[] data = getClassData(name);
  73. if (data != null) {
  74. return defineClass(name, data);
  75. }
  76. }
  77. // Check the other plugins.
  78. for (PluginInfo pi : manager.getPluginInfos()) {
  79. final List<String> classList = pi.getClassList();
  80. if (classList.contains(name) && pi.getPluginClassLoader() != null) {
  81. return pi.getPluginClassLoader().loadClass(name, false);
  82. }
  83. }
  84. throw new ClassNotFoundException("Not found in global classloader:" + name);
  85. }
  86. /**
  87. * Look in all known sources of persistent classes for file asked for.
  88. *
  89. * @param classname Class name to define.
  90. * @param data Data to define class with.
  91. *
  92. * @return The resulting {@link Class} object
  93. */
  94. public Class<?> defineClass(final String classname, final byte... data) {
  95. return defineClass(classname, data, 0, data.length);
  96. }
  97. /**
  98. * Get the requested class from its plugin jar.
  99. *
  100. * @param classname Class to look for.
  101. */
  102. @Nullable
  103. private byte[] getClassData(final String classname) {
  104. try {
  105. final String jarname = resourcesList.get(classname);
  106. if (jarname != null) {
  107. final ResourceManager rm = ResourceManager.getResourceManager("jar://" + jarname);
  108. final String filename = classname.replace('.', '/') + ".class";
  109. if (rm.resourceExists(filename)) {
  110. return rm.getResourceBytes(filename);
  111. }
  112. }
  113. } catch (IOException e) {
  114. // File might have been deleted, oh well.
  115. }
  116. return null;
  117. }
  118. }