Parcourir la source

Use new injector

Tidying

Change-Id: I95bc1fbcfbeac5b101473ad4d87f27dc4880387c
Depends-On: I2ffee5b0dd39f47fd2f319d729213d0cde724c65
Reviewed-on: http://gerrit.dmdirc.com/2063
Automatic-Compile: DMDirc Build Manager
Reviewed-by: Greg Holmes <greg@dmdirc.com>
tags/0.6.6b1
Chris Smith il y a 13 ans
Parent
révision
9bd2686783
2 fichiers modifiés avec 122 ajouts et 145 suppressions
  1. 113
    141
      src/com/dmdirc/plugins/PluginInfo.java
  2. 9
    4
      src/com/dmdirc/plugins/PluginManager.java

+ 113
- 141
src/com/dmdirc/plugins/PluginInfo.java Voir le fichier

@@ -30,22 +30,23 @@ import com.dmdirc.config.InvalidIdentityFileException;
30 30
 import com.dmdirc.logger.ErrorLevel;
31 31
 import com.dmdirc.logger.Logger;
32 32
 import com.dmdirc.updater.Version;
33
+import com.dmdirc.util.SimpleInjector;
33 34
 import com.dmdirc.util.resourcemanager.ResourceManager;
34 35
 import com.dmdirc.util.validators.ValidationResponse;
35 36
 
36 37
 import java.io.File;
37 38
 import java.io.IOException;
38 39
 import java.io.InputStream;
39
-import java.lang.reflect.Constructor;
40
-import java.lang.reflect.InvocationTargetException;
41 40
 import java.util.ArrayList;
42 41
 import java.util.Collection;
42
+import java.util.Collections;
43 43
 import java.util.HashMap;
44 44
 import java.util.List;
45 45
 import java.util.Map;
46 46
 import java.util.Timer;
47 47
 import java.util.TimerTask;
48 48
 import java.util.TreeMap;
49
+import java.util.logging.Level;
49 50
 
50 51
 /**
51 52
  * Stores plugin metadata and handles loading of plugin resources.
@@ -91,18 +92,6 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
91 92
      * @since 0.6.6
92 93
      */
93 94
     public PluginInfo(final PluginMetaData metadata) throws PluginException {
94
-        this(metadata, true);
95
-    }
96
-
97
-    /**
98
-     * Create a new PluginInfo.
99
-     *
100
-     * @param metadata The plugin's metadata information
101
-     * @param load Should this plugin be loaded, or is this just a placeholder? (true for load, false for placeholder)
102
-     * @throws PluginException if there is an error loading the Plugin
103
-     * @since 0.6.6
104
-     */
105
-    public PluginInfo(final PluginMetaData metadata, final boolean load) throws PluginException {
106 95
         this.filename = new File(metadata.getPluginUrl().getPath()).getName();
107 96
         this.metadata = metadata;
108 97
 
@@ -115,11 +104,6 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
115 104
             updateMetaData();
116 105
         }
117 106
 
118
-        if (!load) {
119
-            // TODO: This is pointless now
120
-            return;
121
-        }
122
-
123 107
         if (metadata.hasErrors()) {
124 108
             throw new PluginException("Plugin " + filename + " has metadata "
125 109
                     + "errors: " + metadata.getErrors());
@@ -132,7 +116,7 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
132 116
             throw new PluginException("Plugin " + filename + " failed to load. " + lastError, ioe);
133 117
         }
134 118
 
135
-        final String mainClass = getMainClass().replace('.', '/') + ".class";
119
+        final String mainClass = metadata.getMainClass().replace('.', '/') + ".class";
136 120
         if (!res.resourceExists(mainClass)) {
137 121
             lastError = "main class file (" + mainClass + ") not found in jar.";
138 122
             throw new PluginException("Plugin " + filename + " failed to load. " + lastError);
@@ -150,6 +134,32 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
150 134
         getDefaults();
151 135
     }
152 136
 
137
+    /**
138
+     * Retrieves the injector used to inject parameters into this
139
+     * plugin's methods.
140
+     *
141
+     * @return The injector used for this plugin
142
+     */
143
+    public SimpleInjector getInjector() {
144
+        final SimpleInjector injector;
145
+        if (metadata.getParent() == null || metadata.getParent().isEmpty()) {
146
+            injector = new SimpleInjector();
147
+            injector.addParameter(PluginManager.class,
148
+                    PluginManager.getPluginManager());
149
+            injector.addParameter(ActionManager.class,
150
+                    ActionManager.getActionManager());
151
+        } else {
152
+            final PluginInfo parent = PluginManager.getPluginManager()
153
+                    .getPluginInfoByName(metadata.getParent());
154
+            injector = new SimpleInjector(parent.getInjector());
155
+            injector.addParameter(parent.getPlugin());
156
+        }
157
+
158
+        injector.addParameter(PluginInfo.class, this);
159
+
160
+        return injector;
161
+    }
162
+
153 163
     /**
154 164
      * Get the licence for this plugin if it exists.
155 165
      *
@@ -170,9 +180,10 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
170 180
      */
171 181
     private void getDefaults() {
172 182
         final Identity defaults = IdentityManager.getAddonIdentity();
173
-        final String domain = "plugin-" + getName();
183
+        final String domain = "plugin-" + metadata.getName();
174 184
 
175
-        LOGGER.finer(getName() + ": Using domain '" + domain + "'");
185
+        LOGGER.log(Level.FINER, "{0}: Using domain ''{1}''",
186
+                new Object[]{metadata.getName(), domain});
176 187
 
177 188
         for (Map.Entry<String, String> entry : metadata.getDefaultSettings().entrySet()) {
178 189
             final String key = entry.getKey();
@@ -210,13 +221,8 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
210 221
                 final String name = entry.getKey();
211 222
                 final InputStream stream = entry.getValue();
212 223
 
213
-                if (name.endsWith("/")) {
214
-                    // Don't try to load folders as identities
215
-                    continue;
216
-                }
217
-
218
-                if (stream == null) {
219
-                    //Don't add null streams
224
+                if (name.endsWith("/") || stream == null) {
225
+                    // Don't try to load folders or null streams
220 226
                     continue;
221 227
                 }
222 228
 
@@ -226,12 +232,15 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
226 232
                         IdentityManager.addIdentity(thisIdentity);
227 233
                         identities.add(thisIdentity);
228 234
                     } catch (final InvalidIdentityFileException ex) {
229
-                        Logger.userError(ErrorLevel.MEDIUM, "Error with identity file '" + name + "' in plugin '" + getName() + "'", ex);
235
+                        Logger.userError(ErrorLevel.MEDIUM,
236
+                                "Error with identity file '" + name
237
+                                + "' in plugin '" + metadata.getName() + "'", ex);
230 238
                     }
231 239
                 }
232 240
             }
233 241
         } catch (final IOException ioe) {
234
-            Logger.userError(ErrorLevel.MEDIUM, "Error finding identities in plugin '" + getName() + "'", ioe);
242
+            Logger.userError(ErrorLevel.MEDIUM, "Error finding identities in plugin '"
243
+                    + metadata.getName() + "'", ioe);
235 244
         }
236 245
     }
237 246
 
@@ -370,7 +379,8 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
370 379
     /** {@inheritDoc} */
371 380
     @Override
372 381
     public String getProviderName() {
373
-        return "Plugin: " + getNiceName() + " (" + getName() + " / " + getFilename() + ")";
382
+        return "Plugin: " + metadata.getFriendlyName() + " ("
383
+                + metadata.getName() + " / " + getFilename() + ")";
374 384
     }
375 385
 
376 386
     /** {@inheritDoc} */
@@ -410,7 +420,7 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
410 420
     }
411 421
 
412 422
     /**
413
-     * Load any required plugins
423
+     * Load any required plugins.
414 424
      */
415 425
     public void loadRequired() {
416 426
         final String required = metadata.getRequirements().get("plugins");
@@ -454,11 +464,13 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
454 464
             try {
455 465
                 plugin.onLoad();
456 466
             } catch (LinkageError e) {
457
-                lastError = "Error in onLoad for " + getName() + ":" + e.getMessage();
467
+                lastError = "Error in onLoad for " + metadata.getName() + ":"
468
+                        + e.getMessage();
458 469
                 Logger.userError(ErrorLevel.MEDIUM, lastError, e);
459 470
                 unloadPlugin();
460 471
             } catch (Exception e) {
461
-                lastError = "Error in onLoad for " + getName() + ":" + e.getMessage();
472
+                lastError = "Error in onLoad for " + metadata.getName() + ":"
473
+                        + e.getMessage();
462 474
                 Logger.userError(ErrorLevel.MEDIUM, lastError, e);
463 475
                 unloadPlugin();
464 476
             }
@@ -466,7 +478,7 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
466 478
             isLoading = true;
467 479
             loadIdentities();
468 480
             loadRequired();
469
-            loadClass(getMainClass());
481
+            loadClass(metadata.getMainClass());
470 482
 
471 483
             if (isLoaded()) {
472 484
                 ActionManager.getActionManager().triggerEvent(
@@ -507,44 +519,51 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
507 519
     /**
508 520
      * Checks if this plugin has any children.
509 521
      *
510
-     * @return true iif this plugin has children
522
+     * @return true iff this plugin has children
511 523
      */
512 524
     public boolean hasChildren() {
513 525
         return !children.isEmpty();
514 526
     }
515 527
 
516 528
     /**
517
-     * Load the given classname.
518
-     *
519
-     * @param classname Class to load
529
+     * Initialises this plugin's classloader.
520 530
      */
521
-    private void loadClass(final String classname) {
522
-        try {
523
-            if (classloader == null) {
524
-                if (metadata.getParent() == null) {
525
-                    classloader = new PluginClassLoader(this);
531
+    private void initialiseClassLoader() {
532
+        if (classloader == null) {
533
+            if (metadata.getParent() == null) {
534
+                classloader = new PluginClassLoader(this);
535
+            } else {
536
+                final String parentName = metadata.getParent();
537
+                final PluginInfo pi = PluginManager.getPluginManager().getPluginInfoByName(parentName);
538
+                if (pi == null) {
539
+                    lastError = "Required parent '" + parentName + "' was not found";
540
+                    return;
526 541
                 } else {
527
-                    final String parentName = metadata.getParent();
528
-                    final PluginInfo pi = PluginManager.getPluginManager().getPluginInfoByName(parentName);
529
-                    if (pi == null) {
530
-                        lastError = "Required parent '" + parentName + "' was not found";
531
-                        return;
532
-                    } else {
533
-                        pi.addChild(this);
534
-                        PluginClassLoader parentCL = pi.getPluginClassLoader();
542
+                    pi.addChild(this);
543
+                    PluginClassLoader parentCL = pi.getPluginClassLoader();
544
+                    if (parentCL == null) {
545
+                        // Parent appears not to be loaded.
546
+                        pi.loadPlugin();
547
+                        parentCL = pi.getPluginClassLoader();
535 548
                         if (parentCL == null) {
536
-                            // Parent appears not to be loaded.
537
-                            pi.loadPlugin();
538
-                            parentCL = pi.getPluginClassLoader();
539
-                            if (parentCL == null) {
540
-                                lastError = "Unable to get classloader from required parent '" + parentName + "' for "+getName();
541
-                                return;
542
-                            }
549
+                            lastError = "Unable to get classloader from required parent '" + parentName + "' for "+getName();
550
+                            return;
543 551
                         }
544
-                        classloader = parentCL.getSubClassLoader(this);
545 552
                     }
553
+                    classloader = parentCL.getSubClassLoader(this);
546 554
                 }
547 555
             }
556
+        }
557
+    }
558
+
559
+    /**
560
+     * Load the given classname.
561
+     *
562
+     * @param classname Class to load
563
+     */
564
+    private void loadClass(final String classname) {
565
+        try {
566
+            initialiseClassLoader();
548 567
 
549 568
             // Don't reload a class if its already loaded.
550 569
             if (classloader.isClassLoaded(classname, true)) {
@@ -561,29 +580,34 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
561 580
             // Only try and construct the main class, anything else should be constructed
562 581
             // by the plugin itself.
563 582
             if (classname.equals(metadata.getMainClass())) {
564
-                final Object temp = createInstance(clazz);
583
+                final Object temp = getInjector().createInstance(clazz);
565 584
 
566 585
                 if (temp instanceof Plugin) {
567 586
                     final ValidationResponse prerequisites = ((Plugin) temp).checkPrerequisites();
568 587
                     if (prerequisites.isFailure()) {
569 588
                         if (!tempLoaded) {
570
-                            lastError = "Prerequisites for plugin not met. ('" + filename + ":" + getMainClass() + "' -> '" + prerequisites.getFailureReason() + "') ";
589
+                            lastError = "Prerequisites for plugin not met. ('"
590
+                                    + filename + ":" + metadata.getMainClass()
591
+                                    + "' -> '" + prerequisites.getFailureReason() + "') ";
571 592
                             Logger.userError(ErrorLevel.LOW, lastError);
572 593
                         }
573 594
                     } else {
574 595
                         plugin = (Plugin) temp;
575
-                        LOGGER.finer(getName() + ": Setting domain 'plugin-" + getName() + "'");
596
+                        LOGGER.log(Level.FINER, "{0}: Setting domain ''plugin-{0}''",
597
+                                new Object[]{metadata.getName()});
576 598
                         plugin.setPluginInfo(this);
577
-                        plugin.setDomain("plugin-" + getName());
599
+                        plugin.setDomain("plugin-" + metadata.getName());
578 600
                         if (!tempLoaded) {
579 601
                             try {
580 602
                                 plugin.onLoad();
581 603
                             } catch (LinkageError e) {
582
-                                lastError = "Error in onLoad for " + getName() + ":" + e.getMessage();
604
+                                lastError = "Error in onLoad for "
605
+                                        + metadata.getName() + ":" + e.getMessage();
583 606
                                 Logger.userError(ErrorLevel.MEDIUM, lastError, e);
584 607
                                 unloadPlugin();
585 608
                             } catch (Exception e) {
586
-                                lastError = "Error in onLoad for " + getName() + ":" + e.getMessage();
609
+                                lastError = "Error in onLoad for "
610
+                                        + metadata.getName() + ":" + e.getMessage();
587 611
                                 Logger.userError(ErrorLevel.MEDIUM, lastError, e);
588 612
                                 unloadPlugin();
589 613
                             }
@@ -592,14 +616,28 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
592 616
                 }
593 617
             }
594 618
         } catch (ClassNotFoundException cnfe) {
595
-            lastError = "Class not found ('" + filename + ":" + classname + ":" + classname.equals(getMainClass()) + "') - " + cnfe.getMessage();
619
+            lastError = "Class not found ('" + filename + ":" + classname + ":"
620
+                    + classname.equals(metadata.getMainClass()) + "') - "
621
+                    + cnfe.getMessage();
596 622
             Logger.userError(ErrorLevel.LOW, lastError, cnfe);
597 623
         } catch (NoClassDefFoundError ncdf) {
598
-            lastError = "Unable to instantiate plugin ('" + filename + ":" + classname + ":" + classname.equals(getMainClass()) + "') - Unable to find class: " + ncdf.getMessage();
624
+            lastError = "Unable to instantiate plugin ('" + filename + ":"
625
+                    + classname + ":"
626
+                    + classname.equals(metadata.getMainClass())
627
+                    + "') - Unable to find class: " + ncdf.getMessage();
599 628
             Logger.userError(ErrorLevel.LOW, lastError, ncdf);
600 629
         } catch (VerifyError ve) {
601
-            lastError = "Unable to instantiate plugin ('" + filename + ":" + classname + ":" + classname.equals(getMainClass()) + "') - Incompatible: " + ve.getMessage();
630
+            lastError = "Unable to instantiate plugin ('" + filename + ":"
631
+                    + classname + ":"
632
+                    + classname.equals(metadata.getMainClass())
633
+                    + "') - Incompatible: " + ve.getMessage();
602 634
             Logger.userError(ErrorLevel.LOW, lastError, ve);
635
+        } catch (IllegalArgumentException ex) {
636
+            lastError = "Unable to instantiate plugin ('" + filename + ":"
637
+                    + classname + ":"
638
+                    + classname.equals(metadata.getMainClass())
639
+                    + "') - Unable to construct: " + ex.getMessage();
640
+            Logger.userError(ErrorLevel.LOW, lastError, ex);
603 641
         }
604 642
     }
605 643
 
@@ -624,74 +662,6 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
624 662
                 && metadata.isUnloadable();
625 663
     }
626 664
 
627
-    /**
628
-     * Creates a new instance of the specified class facilitating basic
629
-     * dependency injection.
630
-     *
631
-     * @param clazz The class to be instantiated
632
-     * @return A new instance of the specified class, or null if no suitable
633
-     * constructor could be found and created.
634
-     */
635
-    private Object createInstance(final Class<?> clazz) {
636
-        // Create a map of classes we're willing to inject
637
-        final Map<Class<?>, Object> implementations
638
-                = new HashMap<Class<?>, Object>();
639
-        implementations.put(PluginInfo.class, this);
640
-        implementations.put(PluginManager.class, PluginManager.getPluginManager());
641
-        implementations.put(ActionManager.class, ActionManager.getActionManager());
642
-
643
-        // Add the parent plugin
644
-        if (metadata.getParent() != null && !metadata.getParent().isEmpty()) {
645
-            // TODO: This should recurse to the parent's parent etc too
646
-            final Object parent = PluginManager.getPluginManager().getPluginInfoByName(metadata.getParent()).getPlugin();
647
-
648
-            // Iterate the object hierarchy up
649
-            Class<?> target = parent.getClass();
650
-            do {
651
-                implementations.put(target, parent);
652
-                target = target.getSuperclass();
653
-            } while (target != null);
654
-
655
-            // Add all interfaces
656
-            for (Class<?> parentClazz : parent.getClass().getInterfaces()) {
657
-                implementations.put(parentClazz, parent);
658
-            }
659
-        }
660
-
661
-        for (Constructor<?> ctor : clazz.getConstructors()) {
662
-            final Object[] args = new Object[ctor.getParameterTypes().length];
663
-
664
-            int i = 0;
665
-            for (Class<?> paramType : ctor.getParameterTypes()) {
666
-                if (implementations.containsKey(paramType)) {
667
-                    args[i++] = implementations.get(paramType);
668
-                } else {
669
-                    break;
670
-                }
671
-            }
672
-
673
-            if (i == args.length) {
674
-                try {
675
-                    return ctor.newInstance(args);
676
-                } catch (IllegalAccessException ex) {
677
-                    lastError = "Unable to create new instance of plugin "
678
-                            + filename + ": " + ex.getMessage();
679
-                } catch (IllegalArgumentException ex) {
680
-                    lastError = "Unable to create new instance of plugin "
681
-                            + filename + ": " + ex.getMessage();
682
-                } catch (InstantiationException ex) {
683
-                    lastError = "Unable to create new instance of plugin "
684
-                            + filename + ": " + ex.getMessage();
685
-                } catch (InvocationTargetException ex) {
686
-                    lastError = "Unable to create new instance of plugin "
687
-                            + filename + ": " + ex.getMessage();
688
-                }
689
-            }
690
-        }
691
-
692
-        return null;
693
-    }
694
-
695 665
     /**
696 666
      * Unload the plugin if possible.
697 667
      *
@@ -718,10 +688,12 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
718 688
                 try {
719 689
                     plugin.onUnload();
720 690
                 } catch (Exception e) {
721
-                    lastError = "Error in onUnload for " + getName() + ":" + e + " - " + e.getMessage();
691
+                    lastError = "Error in onUnload for " + metadata.getName()
692
+                            + ":" + e + " - " + e.getMessage();
722 693
                     Logger.userError(ErrorLevel.MEDIUM, lastError, e);
723 694
                 } catch (LinkageError e) {
724
-                    lastError = "Error in onUnload for " + getName() + ":" + e + " - " + e.getMessage();
695
+                    lastError = "Error in onUnload for " + metadata.getName()
696
+                            + ":" + e + " - " + e.getMessage();
725 697
                     Logger.userError(ErrorLevel.MEDIUM, lastError, e);
726 698
                 }
727 699
 
@@ -757,7 +729,7 @@ public class PluginInfo implements Comparable<PluginInfo>, ServiceProvider {
757 729
      * @return Classes this plugin has
758 730
      */
759 731
     public List<String> getClassList() {
760
-        return myClasses;
732
+        return Collections.unmodifiableList(myClasses);
761 733
     }
762 734
 
763 735
     /**

+ 9
- 4
src/com/dmdirc/plugins/PluginManager.java Voir le fichier

@@ -261,7 +261,8 @@ public class PluginManager implements ActionListener {
261 261
         }
262 262
 
263 263
         if (!new File(getDirectory() + filename).exists()) {
264
-            Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": File does not exist");
264
+            Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin "
265
+                    + filename + ": File does not exist");
265 266
             return false;
266 267
         }
267 268
 
@@ -274,7 +275,9 @@ public class PluginManager implements ActionListener {
274 275
             final PluginInfo pluginInfo = new PluginInfo(metadata);
275 276
             final PluginInfo existing = getPluginInfoByName(metadata.getName());
276 277
             if (existing != null) {
277
-                Logger.userError(ErrorLevel.MEDIUM, "Duplicate Plugin detected, Ignoring. (" + filename + " is the same as " + existing.getFilename() + ")");
278
+                Logger.userError(ErrorLevel.MEDIUM,
279
+                        "Duplicate Plugin detected, Ignoring. (" + filename
280
+                        + " is the same as " + existing.getFilename() + ")");
278 281
                 return false;
279 282
             }
280 283
             new PluginComponent(pluginInfo);
@@ -285,9 +288,11 @@ public class PluginManager implements ActionListener {
285 288
                     CoreActionType.PLUGIN_REFRESH, null, this);
286 289
             return true;
287 290
         } catch (MalformedURLException mue) {
288
-            Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin " + filename + ": " + mue.getMessage(), mue);
291
+            Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin "
292
+                    + filename + ": " + mue.getMessage(), mue);
289 293
         } catch (PluginException e) {
290
-            Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": " + e.getMessage(), e);
294
+            Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin "
295
+                    + filename + ": " + e.getMessage(), e);
291 296
         }
292 297
 
293 298
         return false;

Chargement…
Annuler
Enregistrer