DynamicExtension.java 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.util;
  16. import java.io.FileInputStream;
  17. import java.io.FileNotFoundException;
  18. import java.util.Properties;
  19. import java.util.concurrent.ConcurrentHashMap;
  20. import java.util.logging.Level;
  21. import java.util.logging.Logger;
  22. import com.l2jserver.Config;
  23. /**
  24. * extension loader for l2j
  25. * @author galun
  26. * @version $Id: DynamicExtension.java,v 1.3 2006/05/14 17:19:39 galun Exp $
  27. */
  28. public class DynamicExtension
  29. {
  30. private static Logger _log = Logger.getLogger(DynamicExtension.class.getCanonicalName());
  31. private JarClassLoader _classLoader;
  32. private Properties _prop;
  33. private ConcurrentHashMap<String, Object> _loadedExtensions;
  34. private ConcurrentHashMap<String, ExtensionFunction> _getters;
  35. private ConcurrentHashMap<String, ExtensionFunction> _setters;
  36. /**
  37. * create an instance of DynamicExtension
  38. * this will be done by GameServer according to the altsettings.properties
  39. *
  40. */
  41. private DynamicExtension()
  42. {
  43. _getters = new ConcurrentHashMap<String, ExtensionFunction>();
  44. _setters = new ConcurrentHashMap<String, ExtensionFunction>();
  45. initExtensions();
  46. }
  47. /**
  48. * get the singleton of DynamicInstance
  49. * @return the singleton instance
  50. */
  51. public static DynamicExtension getInstance()
  52. {
  53. return SingletonHolder._instance;
  54. }
  55. /**
  56. * get an extension object by class name
  57. * @param className he class name as defined in the extension properties
  58. * @return the object or null if not found
  59. */
  60. public Object getExtension(String className)
  61. {
  62. return _loadedExtensions.get(className);
  63. }
  64. /**
  65. * initialize all configured extensions
  66. *
  67. */
  68. public String initExtensions()
  69. {
  70. _prop = new Properties();
  71. String res = "";
  72. _loadedExtensions = new ConcurrentHashMap<String, Object>();
  73. try
  74. {
  75. _prop.load(new FileInputStream(Config.EXTENSIONS_CONFIG_FILE));
  76. }
  77. catch (FileNotFoundException ex)
  78. {
  79. _log.info(ex.getMessage() + ": no extensions to load");
  80. }
  81. catch (Exception ex)
  82. {
  83. _log.log(Level.WARNING, "could not load properties", ex);
  84. }
  85. _classLoader = new JarClassLoader();
  86. for (Object o : _prop.keySet())
  87. {
  88. String k = (String) o;
  89. if (k.endsWith("Class"))
  90. {
  91. res += initExtension(_prop.getProperty(k)) + "\n";
  92. }
  93. }
  94. return res;
  95. }
  96. /**
  97. * init a named extension
  98. * @param name the class name and optionally a jar file name delimited with a '@' if the jar file is not
  99. * in the class path
  100. */
  101. public String initExtension(String name)
  102. {
  103. String className = name;
  104. String[] p = name.split("@");
  105. String res = name + " loaded";
  106. if (p.length > 1)
  107. {
  108. _classLoader.addJarFile(p[1]);
  109. className = p[0];
  110. }
  111. if (_loadedExtensions.containsKey(className))
  112. return "already loaded";
  113. try
  114. {
  115. Class<?> extension = Class.forName(className, true, _classLoader);
  116. Object obj = extension.newInstance();
  117. extension.getMethod("init", new Class[0]).invoke(obj, new Object[0]);
  118. _log.info("Extension " + className + " loaded.");
  119. _loadedExtensions.put(className, obj);
  120. }
  121. catch (Exception ex)
  122. {
  123. _log.log(Level.WARNING, name, ex);
  124. res = ex.toString();
  125. }
  126. return res;
  127. }
  128. /**
  129. * create a new class loader which resets the cache (jar files and loaded classes)
  130. * on next class loading request it will read the jar again
  131. */
  132. protected void clearCache()
  133. {
  134. _classLoader = new JarClassLoader();
  135. }
  136. /**
  137. * call unloadExtension() for all known extensions
  138. *
  139. */
  140. public String unloadExtensions()
  141. {
  142. String res = "";
  143. for (String e : _loadedExtensions.keySet())
  144. res += unloadExtension(e) + "\n";
  145. return res;
  146. }
  147. /**
  148. * get all loaded extensions
  149. * @return a String array with the class names
  150. */
  151. public String[] getExtensions()
  152. {
  153. String[] l = new String[_loadedExtensions.size()];
  154. _loadedExtensions.keySet().toArray(l);
  155. return l;
  156. }
  157. /**
  158. * unload a named extension
  159. * @param name the class name and optionally a jar file name delimited with a '@'
  160. */
  161. public String unloadExtension(String name)
  162. {
  163. String className = name;
  164. String[] p = name.split("@");
  165. if (p.length > 1)
  166. {
  167. _classLoader.addJarFile(p[1]);
  168. className = p[0];
  169. }
  170. String res = className + " unloaded";
  171. try
  172. {
  173. Object obj = _loadedExtensions.get(className);
  174. Class<?> extension = obj.getClass();
  175. _loadedExtensions.remove(className);
  176. extension.getMethod("unload", new Class[0]).invoke(obj, new Object[0]);
  177. _log.info("Extension " + className + " unloaded.");
  178. }
  179. catch (Exception ex)
  180. {
  181. _log.log(Level.WARNING, "could not unload " + className, ex);
  182. res = ex.toString();
  183. }
  184. return res;
  185. }
  186. /**
  187. * unloads all extensions, resets the cache and initializes all configured extensions
  188. *
  189. */
  190. public void reload()
  191. {
  192. unloadExtensions();
  193. clearCache();
  194. initExtensions();
  195. }
  196. /**
  197. * unloads a named extension, resets the cache and initializes the extension
  198. * @param name the class name and optionally a jar file name delimited with a '@' if the jar file is not
  199. * in the class path
  200. */
  201. public void reload(String name)
  202. {
  203. unloadExtension(name);
  204. clearCache();
  205. initExtension(name);
  206. }
  207. /**
  208. * register a getter function given a (hopefully) unique name
  209. * @param name the name of the function
  210. * @param function the ExtensionFunction implementation
  211. */
  212. public void addGetter(String name, ExtensionFunction function)
  213. {
  214. _getters.put(name, function);
  215. }
  216. /**
  217. * deregister a getter function
  218. * @param name the name used for registering
  219. */
  220. public void removeGetter(String name)
  221. {
  222. _getters.remove(name);
  223. }
  224. /**
  225. * call a getter function registered with DynamicExtension
  226. * @param name the function name
  227. * @param arg a function argument
  228. * @return an object from the extension
  229. */
  230. public Object get(String name, String arg)
  231. {
  232. ExtensionFunction func = _getters.get(name);
  233. if (func != null)
  234. return func.get(arg);
  235. return "<none>";
  236. }
  237. /**
  238. * register a setter function given a (hopefully) unique name
  239. * @param name the name of the function
  240. * @param function the ExtensionFunction implementation
  241. */
  242. public void addSetter(String name, ExtensionFunction function)
  243. {
  244. _setters.put(name, function);
  245. }
  246. /**
  247. * deregister a setter function
  248. * @param name the name used for registering
  249. */
  250. public void removeSetter(String name)
  251. {
  252. _setters.remove(name);
  253. }
  254. /**
  255. * call a setter function registered with DynamicExtension
  256. * @param name the function name
  257. * @param arg a function argument
  258. * @param obj an object to set
  259. */
  260. public void set(String name, String arg, Object obj)
  261. {
  262. ExtensionFunction func = _setters.get(name);
  263. if (func != null)
  264. func.set(arg, obj);
  265. }
  266. public JarClassLoader getClassLoader()
  267. {
  268. return _classLoader;
  269. }
  270. @SuppressWarnings("synthetic-access")
  271. private static class SingletonHolder
  272. {
  273. protected static final DynamicExtension _instance = new DynamicExtension();
  274. }
  275. }