PageRenderTime 37ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mpv5/pluginhandling/YabsPluginLoader.java

http://mp-rechnungs-und-kundenverwaltung.googlecode.com/
Java | 374 lines | 265 code | 29 blank | 80 comment | 32 complexity | c5ec730a3104cb679dc8653d5d165584 MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0, GPL-3.0, GPL-2.0, AGPL-3.0, JSON, BSD-3-Clause
  1. /*
  2. * This file is part of YaBS.
  3. *
  4. * YaBS is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * YaBS is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with YaBS. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package mpv5.pluginhandling;
  18. import java.awt.Component;
  19. import java.awt.Image;
  20. import java.awt.event.ActionEvent;
  21. import java.awt.event.ActionListener;
  22. import java.awt.event.MouseAdapter;
  23. import java.awt.event.MouseEvent;
  24. import java.awt.image.BufferedImage;
  25. import java.io.File;
  26. import java.io.FileNotFoundException;
  27. import java.net.URL;
  28. import java.net.URLClassLoader;
  29. import java.net.URLStreamHandlerFactory;
  30. import java.util.ArrayList;
  31. import java.util.Arrays;
  32. import java.util.List;
  33. import java.util.Vector;
  34. import java.util.logging.Level;
  35. import java.util.logging.Logger;
  36. import javax.imageio.ImageIO;
  37. import javax.swing.Icon;
  38. import javax.swing.ImageIcon;
  39. import javax.swing.JComponent;
  40. import javax.swing.JLabel;
  41. import javax.swing.JMenuItem;
  42. import javax.swing.JPopupMenu;
  43. import mpv5.Main;
  44. import mpv5.YabsViewProxy;
  45. import mpv5.db.common.Context;
  46. import mpv5.db.common.NodataFoundException;
  47. import mpv5.db.common.QueryCriteria;
  48. import mpv5.db.common.DatabaseObject;
  49. import mpv5.db.common.DatabaseObjectModifier;
  50. import mpv5.db.common.QueryHandler;
  51. import mpv5.globals.Constants;
  52. import mpv5.globals.LocalSettings;
  53. import mpv5.globals.Messages;
  54. import mpv5.logging.Log;
  55. import mpv5.ui.dialogs.Popup;
  56. import mpv5.ui.frames.MPView;
  57. import mpv5.utils.images.MPIcon;
  58. /**
  59. *
  60. * This class loads plugins from the database, and utilises caching of the plugin files.
  61. */
  62. public class YabsPluginLoader {
  63. public static String pluginSignature = LocalSettings.getProperty(LocalSettings.CACHE_DIR) + File.separator + "%%filename%%-yabs.jar";
  64. public static List<DatabaseObjectModifier> registeredModifiers = new Vector<DatabaseObjectModifier>();
  65. public static Image getDefaultPluginImage() {
  66. BufferedImage img = null;
  67. try {
  68. img = ImageIO.read(YabsPluginLoader.class.getResource("/mpv5/resources/images/48/blockdevice.png"));
  69. } catch (Exception e) {
  70. Log.Debug(e);
  71. }
  72. return img;
  73. }
  74. public static Image getErrorImage() {
  75. BufferedImage img = null;
  76. try {
  77. img = ImageIO.read(YabsPluginLoader.class.getResource("/mpv5/resources/images/48/messagebox_question.png"));
  78. } catch (Exception e) {
  79. Log.Debug(e);
  80. }
  81. return img;
  82. }
  83. public static void importPlugin(String name, File file) throws FileNotFoundException {
  84. mpv5.YabsViewProxy.instance().setWaiting(true);
  85. try {
  86. YabsPlugin pl = YabsPluginLoader.checkPlugin(file);
  87. try {
  88. Thread.sleep(10000);
  89. } catch (InterruptedException ex) {
  90. Logger.getLogger(YabsPluginLoader.class.getName()).log(Level.SEVERE, null, ex);
  91. }
  92. if (pl != null) {
  93. String s = name;
  94. if (s != null) {
  95. String filename = QueryHandler.instanceOf().clone(Context.getFiles()).insertFile(file);
  96. Plugin p = new Plugin();
  97. p.setDescription(s);
  98. p.setCname("Plugin: " + pl.getName());
  99. p.setFilename(filename);
  100. p.save();
  101. }
  102. }
  103. } catch (FileNotFoundException fileNotFoundException) {
  104. Popup.error(mpv5.Main.getApplication().getMainFrame(), "Your database seems slow, try again :-/");
  105. } finally {
  106. mpv5.YabsViewProxy.instance().setWaiting(false);
  107. }
  108. }
  109. /**
  110. * Loads all plugins which are assigned to the current logged in user from database or cache dir<br/>
  111. * does NOT call plugin.load()
  112. * @return An array of instantiated plugins
  113. */
  114. public static YabsPlugin[] getPlugins() {
  115. ArrayList<YabsPlugin> list = null;
  116. try {
  117. list = new ArrayList<YabsPlugin>();
  118. ArrayList<File> jars = new ArrayList<File>();
  119. QueryCriteria criterias = new QueryCriteria("usersids", mpv5.db.objects.User.getCurrentUser().__getIDS());
  120. try {
  121. ArrayList<UserPlugin> data = DatabaseObject.getObjects(Context.getPluginsToUsers(), criterias);
  122. for (int i = 0; i < data.size(); i++) {
  123. UserPlugin up = data.get(i);
  124. Plugin o = ((Plugin) DatabaseObject.getObject(Context.getPlugins(), up.__getPluginsids()));
  125. Log.Debug(YabsPluginLoader.class, "Found Plugin: " + o);
  126. if (!isCachedPlugin(o.__getFilename())) {
  127. Log.Debug(YabsPluginLoader.class, "Caching plugin: " + pluginSignature.replace("%%filename%%", o.__getFilename()));
  128. jars.add(QueryHandler.instanceOf().clone(Context.getFiles()).retrieveFile(o.__getFilename(), new File(pluginSignature.replace("%%filename%%", o.__getFilename()))));
  129. } else {
  130. Log.Debug(YabsPluginLoader.class, "Using cached plugin: " + pluginSignature.replace("%%filename%%", o.__getFilename()));
  131. jars.add(new File(pluginSignature.replace("%%filename%%", o.__getFilename())));
  132. }
  133. }
  134. } catch (NodataFoundException ex) {
  135. Log.Debug(YabsPluginLoader.class, "No plugins found: " + ex.getMessage());
  136. }
  137. for (int i = 0; i < jars.size(); i++) {
  138. File x = jars.get(i);
  139. YabsPlugin c = checkPlugin(x);
  140. if (c != null) {
  141. list.add(c);
  142. }
  143. }
  144. } catch (Exception e) {
  145. Popup.error(e);
  146. Log.Debug(e);
  147. }
  148. return list.toArray(new YabsPlugin[0]);
  149. }
  150. /**
  151. * Checks if the plugin is already cached
  152. * @param filename
  153. * @return false if the file DOES NOT EXIST in the plugin cache directory, true otherwise
  154. */
  155. public static boolean isCachedPlugin(String filename) {
  156. File f = new File(pluginSignature.replace("%%filename%%", filename));
  157. Log.Debug(YabsPluginLoader.class, "Checking cache for " + filename);
  158. return f.exists() && f.canRead() && (checkPlugin(f) != null);
  159. }
  160. /**
  161. * Checks if the given file is a valid plugin
  162. * @param pluginCandidate
  163. * @return the plugin if <code>Constants.PLUGIN_LOAD_CLASS<code/> could be instantiated from this file
  164. */
  165. public static YabsPlugin checkPlugin(final File pluginCandidate) {
  166. try {
  167. URL[] urls = {new URL("jar:file:" + pluginCandidate + "!/")};
  168. URLClassLoader loader = new AddURLClassLoader(urls, Main.getApplication().getClass().getClassLoader());
  169. Class c = loader.loadClass(Constants.PLUGIN_LOAD_CLASS);
  170. Object o = c.newInstance();
  171. Log.Print(Arrays.asList(o.getClass().getInterfaces()));
  172. return (YabsPlugin) o;
  173. } catch (Exception malformedURLException) {
  174. Log.Debug(malformedURLException);
  175. Popup.error(malformedURLException);
  176. return null;
  177. }
  178. }
  179. /**
  180. * A nifty classloader
  181. */
  182. public static class AddURLClassLoader extends URLClassLoader {
  183. public AddURLClassLoader(URL[] urls, ClassLoader parent) {
  184. super(urls, parent);
  185. }
  186. public AddURLClassLoader(URL[] urls) {
  187. super(urls);
  188. }
  189. public AddURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
  190. super(urls, parent, factory);
  191. }
  192. @Override
  193. public void addURL(URL url) {
  194. super.addURL(url);
  195. }
  196. }
  197. /**
  198. *
  199. * @param file
  200. * @return
  201. */
  202. public YabsPlugin getPlugin(File file) {
  203. return checkPlugin(file);
  204. }
  205. /**
  206. * Load all queued plugins
  207. */
  208. public static void loadPlugins() throws Exception, Throwable {
  209. for (int i = 0; i < pluginstoBeLoaded.size(); i++) {
  210. YabsPlugin YabsPlugin = pluginstoBeLoaded.get(i);
  211. loadPlugin(YabsPlugin);
  212. }
  213. }
  214. /**
  215. * Queues plugins to be loaded after the main Frame is showing.</br>
  216. * Adding plugins AFTER the main Frame is constructed will result in nothing.</br>
  217. * Use {@link loadPlugin(YabsPlugin)} instead.
  218. * @param plugins
  219. */
  220. public static void queuePlugins() {
  221. pluginstoBeLoaded.addAll(Arrays.asList(getPlugins()));
  222. }
  223. private static ArrayList<YabsPlugin> pluginstoBeLoaded = new ArrayList<YabsPlugin>();
  224. /**
  225. * Unloads the plugin and notifies the main view about the unload
  226. * @param YabsPlugin
  227. */
  228. public static void unLoadPlugin(YabsPlugin YabsPlugin) {
  229. YabsPlugin.unload();
  230. loadedPlugs.remove(YabsPlugin.getUID());
  231. // Component[] c = mpv5.YabsViewProxy.instance().getIdentifierView().getPluginIcons().getComponents();
  232. // for (int i = 0; i < c.length; i++) {
  233. // Component component = c[i];
  234. // if (((JLabel) component).getToolTipText().contains(String.valueOf(YabsPlugin.getUID()))) {
  235. //// mpv5.YabsViewProxy.instance().getIdentifierView().getPluginIcons().remove(component);
  236. // }
  237. // }
  238. mpv5.YabsViewProxy.instance().getIdentifierFrame().validate();
  239. mpv5.YabsViewProxy.instance().getIdentifierFrame().repaint();
  240. YabsPlugin = null;
  241. System.gc();
  242. }
  243. /**
  244. * Loads the given plugin (by calling <code>plugin.load(this)<code/>). If the plugin is a visible plugin, adds it to the main tab pane.</br>
  245. * If it is a <code>Runnable<code/>, it will be started on an new thread.
  246. * @param gin
  247. */
  248. public void loadPlugin(Plugin gin) throws Exception, Throwable {
  249. YabsPlugin plo = new mpv5.pluginhandling.YabsPluginLoader().getPlugin(QueryHandler.instanceOf().clone(Context.getFiles()).retrieveFile(gin.__getFilename()));
  250. if (plo != null) {
  251. loadPlugin(plo);
  252. } else {
  253. Log.Debug(this, "Plugin not loaded: " + plo);
  254. }
  255. }
  256. private static final List<Long> loadedPlugs = new Vector<Long>();
  257. /**
  258. * Loads the given plugin (by calling <code>plugin.load(this)<code/>). If the plugin is a visible plugin, adds it to the main tab pane.</br>
  259. * If it is a <code>Runnable<code/>, it will be started on an new thread.
  260. * @param yplugin
  261. * @throws Exception
  262. * @throws Throwable
  263. */
  264. public static void loadPlugin(final YabsPlugin yplugin) throws Exception, Throwable {
  265. if (!loadedPlugs.contains(yplugin.getUID()) && yplugin.isEnabled()) {
  266. loadedPlugs.add(yplugin.getUID());
  267. final JLabel plab = new JLabel();
  268. plab.setDisabledIcon(new MPIcon(YabsPluginLoader.getErrorImage()).getIcon(18));
  269. try {
  270. try {
  271. Log.Debug(YabsPluginLoader.class, "Plugin: \n"
  272. + "Name: " + yplugin.getName() + "\n"
  273. + "Vendor: " + yplugin.getVendor() + "\n"
  274. + "IsComponent: " + yplugin.isComponent() + "\n"
  275. + "IsRunnable: " + yplugin.isRunnable());
  276. yplugin.load(Main.getApplication().getMainView());
  277. } catch (Exception e) {
  278. Log.Debug(YabsPluginLoader.class, e.getMessage());
  279. Log.Debug(YabsPluginLoader.class, "Incompatible plugin found, asking to load anyway..");
  280. if (!Popup.Y_N_dialog(Messages.PLUGIN_INCOMPATIBLE, e)) {
  281. loadedPlugs.remove(yplugin.getUID());
  282. return;
  283. }
  284. }
  285. if (yplugin instanceof DatabaseObjectModifier) {
  286. Log.Debug(YabsPluginLoader.class, "Register modifying plugins: " + yplugin);
  287. registeredModifiers.add((DatabaseObjectModifier) yplugin);
  288. }
  289. if (yplugin.isComponent()) {
  290. mpv5.YabsViewProxy.instance().getIdentifierView().addTab((JComponent) yplugin, yplugin.getName());
  291. }
  292. if (yplugin.isRunnable() && yplugin.isLoaded()) {
  293. Thread t = new Thread((Runnable) yplugin);
  294. t.start();
  295. }
  296. if (yplugin.getIcon() != null) {
  297. plab.setIcon(new MPIcon(yplugin.getIcon()).getIcon(18));
  298. } else {
  299. plab.setIcon(new MPIcon(YabsPluginLoader.getDefaultPluginImage()).getIcon(18));
  300. }
  301. plab.setToolTipText("<html><b>" + yplugin.getName() + " " + Messages.LOADED + "</b><br/><font size=-3>[" + yplugin.getUID() + "]</html>");
  302. plab.addMouseListener(new MouseAdapter() {
  303. @Override
  304. public void mouseReleased(MouseEvent e) {
  305. if (e.getButton() == MouseEvent.BUTTON2 || e.getButton() == MouseEvent.BUTTON3) {
  306. JLabel source = (JLabel) e.getSource();
  307. JPopupMenu m = new JPopupMenu();
  308. JMenuItem n = new JMenuItem(Messages.UNLOAD.getValue());
  309. n.addActionListener(new ActionListener() {
  310. @Override
  311. public void actionPerformed(ActionEvent e) {
  312. unLoadPlugin(yplugin);
  313. mpv5.Main.getApplication().getMainView().getMenuBar().remove(plab);
  314. mpv5.Main.getApplication().getMainView().getMenuBar().validate();
  315. }
  316. });
  317. m.add(n);
  318. m.show(plab, e.getX(), e.getY());
  319. }
  320. }
  321. });
  322. try {
  323. Main.getApplication().getMainView().getMenuBar().add(plab);
  324. mpv5.Main.getApplication().getMainView().getMenuBar().validate();
  325. } catch (Exception e) {
  326. Log.Debug(e);
  327. }
  328. } catch (Throwable e) {
  329. Log.Debug(e);
  330. // plab.setEnabled(false);
  331. throw e;
  332. }
  333. } else {
  334. Popup.notice(Messages.NOT_POSSIBLE + "\n" + yplugin + " is already loaded and doesn't allow multiple instances.");
  335. Log.Debug(YabsPluginLoader.class, "Plugin does not allow multiple instances: " + yplugin);
  336. }
  337. }
  338. /**
  339. * Removes the modifier from the list
  340. * @param m
  341. */
  342. public static void removeModifier(DatabaseObjectModifier m) {
  343. registeredModifiers.remove(m);
  344. }
  345. }