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