Making apps with future extensions

Reply

Join Date: Nov 2005
Posts: 74
Reputation: Cudmore is an unknown quantity at this point 
Solved Threads: 5
Cudmore's Avatar
Cudmore Cudmore is offline Offline
Junior Poster in Training

Making apps with future extensions

 
0
  #1
Jun 11th, 2006
So. I'm having an issue.

I'm building an application that loads class files as extensions during runtime. I'm doing this, becuase I want my application to be able to grow in the future without having to recode and recompile the main source.. So, I plan to make seperate class files that can be loaded at runtime, depending on their existance.

I'm having trouble with loading the classes and calling their methods..

Every extension class will have the following function in common, for example:
  1. public void SetRefs ([ClassName] theobj) {
  2. // Set Object References
  3. myobj = theobj;
  4. }

And my application loads the extensions like so:
  1. private interface ExtensionInf {
  2. public void SetRefs ([ClassName] theobj);
  3. }
  4.  
  5. .....
  6.  
  7. try {
  8.  
  9. String className = classFileName.substring ( 0,
  10. classFileName.lastIndexOf (".")).trim () );
  11.  
  12. Class loaded = Class.forName (className);
  13. // Try to load class object into Java
  14.  
  15. ExtensionInf loadedclassobj = (ExtensionInf)
  16. loaded.getConstructor().newInstance();
  17.  
  18. loadedclassobj.SetRefs(MyObject);
  19.  
  20. } catch (Exception ex) {
  21. // Invalid Extension
  22. AppDebug (ex);
  23. }

I know this doesn't work. I get a ClassCast exception.
So, I can't use the interface like that.
And I tried using *.getClass().getMethod(...).invoke(...);
...but I got an some other error, like, the object wasn't an instance or whatever.

So my question is, as I've searched google for about a total of 2 hours now, tried several different tactics and have grown tired... How, do I load class files using their name, instance them, and access their methods..?

:-|

Thankie!
Reply With Quote Quick reply to this message  
Join Date: Nov 2005
Posts: 74
Reputation: Cudmore is an unknown quantity at this point 
Solved Threads: 5
Cudmore's Avatar
Cudmore Cudmore is offline Offline
Junior Poster in Training

An Example that works

 
0
  #2
Jun 11th, 2006
Here's an example I wrote that works, but it's primitive.

TestExtension.java
  1. public class TestExtension {
  2.  
  3. public static String retClassName () {
  4. return "Class Name: TestClass";
  5. }
  6.  
  7. }

Tester.java
  1. public class Tester{
  2.  
  3. public static void main (String[] args) {
  4. try {
  5. Class loaded = Class.forName ("TestExtension");
  6.  
  7. System.out.println (
  8. loaded.getMethod("retClassName").invoke(loaded)
  9. );
  10.  
  11. } catch (Exception ex) {
  12. System.err.println (ex);
  13. }
  14.  
  15. } // END MAIN
  16.  
  17. }

Running Tester.class (after compiling both) outputs:
  1. Class Name: TestClass
  2. Press any key to continue...
Reply With Quote Quick reply to this message  
Join Date: Nov 2004
Posts: 6,143
Reputation: jwenting is just really nice jwenting is just really nice jwenting is just really nice jwenting is just really nice 
Solved Threads: 212
Team Colleague
jwenting's Avatar
jwenting jwenting is offline Offline
duckman

Re: Making apps with future extensions

 
0
  #3
Jun 12th, 2006
You can actually do pretty much just that, you've almost succeeded in creating your own plugin architecture.

Congratulations on that, it takes many people years to figure out (if they succeed at all).

What you're looking at is an abstract factory to create adapters.

What you need is to create an interface (abstract baseclass would work as well but is far less flexible) which defines the methods that you need for your plugins to function.
Then you can just cast the result from the class instantiation to that interface and you can call any of those methods.
As people are clearly allowed to attack me but I'm not allowed to defend myself, I no longer post to this site.
Reply With Quote Quick reply to this message  
Join Date: Nov 2005
Posts: 74
Reputation: Cudmore is an unknown quantity at this point 
Solved Threads: 5
Cudmore's Avatar
Cudmore Cudmore is offline Offline
Junior Poster in Training

I figured it outttttt!!

 
0
  #4
Jun 19th, 2006
:eek: OH - MY - GOSH.

:cheesy: I figured it out.

I think it's been about a total of.. hmm.. 10 hours, now, trying to get this?
I've been playing with it all morning, and it finally compiled and ran as expected.
All I needed to do was IMPLEMENT the interface -- something I overlooked. Gah.
Thanks, jwenting. Your comment gave me hope and prevented me from deleting everything and trying something completely different. It's your fault that I figured it out! Well, maybe "fault" isn't the word. Anyhow, here's my working code...

Here is the interface I implemented:
  1. public interface CastPlugin {
  2. public void SetPapa(Object PeutEtrePapa); // Set reference to parenting class
  3. public String pluginName(); // Return plugin's short name
  4. public String pluginDescription(); // Return plugin's long description
  5. public String pluginReturnState(); // Return plugin's current condition
  6. public JPanel pluginReturnGUI(); // Return GUI for tab use
  7. public void pluginDie(); // Tell plugin to save data and shut down
  8. }

Here's the contents of a test plugin file: TestPlugin_NWP.java
  1. package plugins;
  2.  
  3. /* NOTE: ALL PLUGINS MUST HAVE A CLASS NAME ENDING WITH "_NWP"
  4.  * AND MUST ALSO BE A PART OF THE "plugins" PACKAGE. */
  5.  
  6. // When I design future plugins and compile, I should just be able
  7. // to distribute the .class files, and the user can place them in
  8. // the "plugins" package directory.. No?? I'll test this theory..
  9.  
  10. import javax.swing.JPanel;
  11.  
  12. /**
  13.  * This is a test plugin to be used with the
  14.  * NetWorker application by Matthew Cudmore.
  15.  *
  16.  * @author Matthew Cudmore
  17.  *
  18.  */
  19. public class TestPlugin_NWP implements brainFiles.GUIBoss.CastPlugin {
  20.  
  21. // NOTICE: I implement the Interface that is defined in the file
  22. // GUIBoss in the package brainFiles. I have to implement the
  23. // interface so that I can cast this class in the future.
  24.  
  25. ////////// CONSTANTS
  26. static final String plugin_author = "Matthew Cudmore";
  27. static final String plugin_version = "1.0 06/19/06";
  28. static final String plugin_title = "Test Plugin";
  29. static final String plugin_description = "Description Here";
  30.  
  31. ////////// PRIVATE VARIABLES
  32. private static String plugin_state = "Ok.";
  33.  
  34. public static void main () {
  35. // Dunno why, but can't get this to run under SuSE 10.1
  36. // No matter how I enter the args to the 'java' command,
  37. // "Exception in thread "main" java.lang.NoClassDefFoundError"
  38. System.out.println (plugin_title + " [Version: "
  39. + plugin_version + "]" );
  40. System.out.println ("By: " + plugin_author);
  41. System.out.println ();
  42. System.out.println (plugin_description);
  43. System.out.println ();
  44. System.out.println ("This Plugin cannot run "
  45. + "independently. Exiting..." );
  46. }
  47.  
  48. // Plugin Constructor(s)
  49. //==============================================================
  50. public TestPlugin_NWP () {
  51. System.out.println ("Plugin loaded: " + plugin_title);
  52. }
  53.  
  54. // Implemented Method Definitions
  55. //==============================================================
  56. public void SetPapa (Object PeutEtrePapa) {
  57. // Use this method to set references...
  58. }
  59.  
  60. public String pluginName() {
  61. // Return plugin's name for tab
  62. return plugin_title;
  63. }
  64.  
  65. public String pluginDescription() {
  66. // Return plugin's long description
  67. return plugin_description;
  68. }
  69.  
  70. public String pluginReturnState() {
  71. // Return plugin's functioning condition
  72. return plugin_state;
  73. }
  74.  
  75. public JPanel pluginReturnGUI() {
  76. // Return GUI for tab use
  77. JPanel plugin_panel = new JPanel();
  78. return plugin_panel;
  79. }
  80.  
  81. public void pluginDie() {
  82. // Tell plugin to close sockets, save data, etc
  83. }
  84.  
  85. // Private Methods
  86. //==============================================================
  87.  
  88. // None: This is a test
  89.  
  90. }

And here are the methods I used to load the plugin:
  1. private static boolean PluginsAlreadyLoaded = false;
  2.  
  3. public void LoadPlugins () {
  4. if (PluginsAlreadyLoaded) return;
  5. File pluginDir = new File ("plugins");
  6. if (pluginDir.exists() && pluginDir.isDirectory()) {
  7. String[] filelist = pluginDir.list();
  8. for (int i = 0; i < filelist.length; i++) {
  9. if (filelist[i].endsWith("_NWP.class")) {
  10. // Only read the file if it is a plugin class
  11. // (the whatever$subclass.class files are ignored)
  12. LoadPlugin (
  13. filelist[i].substring ( 0,
  14. filelist[i].lastIndexOf (".class")
  15. )
  16. );
  17. }
  18. }
  19. PluginsAlreadyLoaded = true;
  20. }
  21. }
  22.  
  23. private void LoadPlugin (String pluginName) {
  24. try {
  25.  
  26. Class lodc = Class.forName("plugins." + pluginName);
  27.  
  28. /* Note: Can't yet cast the Class to an Interface,
  29. * because Interfaces don't have Constructors */
  30.  
  31. Class[] theParams = lodc.getConstructors()[0]
  32. .getParameterTypes();
  33.  
  34. // Assuming there is a constructor...
  35. Object lp = lodc.getConstructor(theParams)
  36. .newInstance(nullParams(theParams));
  37.  
  38. CastPlugin lplugin = (CastPlugin)lp;
  39.  
  40. // Load the plugin's GUI into the JTabbedPane 'jbp_jtp'...
  41. jbp_jtp.add(
  42. lplugin.pluginName(),
  43. lplugin.pluginReturnGUI()
  44. );
  45.  
  46. } catch (Exception ex) {
  47. // IGNORE: Bad Plugin??
  48. NetWorker.LogError(ex); // Log the error elsewhere
  49. }
  50. }
  51.  
  52. private Object[] nullParams (Class[] ptypes) {
  53. // return an Object array of null values of ptypes types
  54. /* This is for compatability -- incase a plugin constructor
  55. * desires random arguments */
  56. Object[] obs = new Object[ptypes.length];
  57. for (int i = 0; i < ptypes.length; i++) obs[i] = null;
  58. return obs;
  59. }
Last edited by Cudmore; Jun 19th, 2006 at 3:41 pm.
Reply With Quote Quick reply to this message  
Join Date: Nov 2005
Posts: 74
Reputation: Cudmore is an unknown quantity at this point 
Solved Threads: 5
Cudmore's Avatar
Cudmore Cudmore is offline Offline
Junior Poster in Training

Re: Making apps with future extensions

 
0
  #5
Jun 19th, 2006
It won't let me edit my previous post, so..

Incase anyone noticed in my code, in the main function I said...
  1. public static void main () {
  2. // Dunno why, but can't get this to run under SuSE 10.1
  3. // No matter how I enter the args to the 'java' command,
  4. // "Exception in thread "main" java.lang.NoClassDefFoundError"

Well I didn't have String[] args :o
And the problen I had originally is that I wasn't entering the command properly.
Correct command: java -classpath . plugins.TestPlugin_NWP
Last edited by Cudmore; Jun 19th, 2006 at 5:59 pm.
Reply With Quote Quick reply to this message  
Join Date: Nov 2005
Posts: 74
Reputation: Cudmore is an unknown quantity at this point 
Solved Threads: 5
Cudmore's Avatar
Cudmore Cudmore is offline Offline
Junior Poster in Training

Re: Making apps with future extensions

 
0
  #6
Jun 19th, 2006
................................................. (Delete this -- Accident Post) .................................................
Last edited by Cudmore; Jun 19th, 2006 at 5:59 pm.
Reply With Quote Quick reply to this message  
Join Date: May 2005
Posts: 19
Reputation: Rotak is an unknown quantity at this point 
Solved Threads: 0
Rotak Rotak is offline Offline
Newbie Poster

Re: Making apps with future extensions

 
0
  #7
Jul 22nd, 2006
Originally Posted by jwenting
What you're looking at is an abstract factory to create adapters.

What you need is to create an interface (abstract baseclass would work as well but is far less flexible) which defines the methods that you need for your plugins to function.
I used a 2-interface-version, which made everything much more flexible and comfortable.

The first interface describes the plugin manager, called PluginManagerInterface. This interface publishes functions like adding menu items, getting program version, adding items to the status bar and so on.

The second interface is the plugin interface. Here I added functions like "init(), start(), stop(), deinit(), getPluginName(), getPluginVersion()"... These functions are called by the plugin manager class (which also implements the plugin manager interface).

The trick is, that the init() function of the plugin looks like this:

public void init(PluginManagerInterface manager)

Now, I can store the manager in a static variable and I am able to access the published manager functions whenever I need to.

The main benefit of this architecture is, that I can publish both interface classes and every customer is able to develop own plugins without knowing anything about my own code, as I don't need to pass a class (which may change) to the plugin's init function.
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Similar Threads
Other Threads in the Java Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC