944,017 Members | Top Members by Rank

Ad:
  • Java Discussion Thread
  • Unsolved
  • Views: 1675
  • Java RSS
Jun 11th, 2006
0

Making apps with future extensions

Expand Post »
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:
Java Syntax (Toggle Plain Text)
  1. public void SetRefs ([ClassName] theobj) {
  2. // Set Object References
  3. myobj = theobj;
  4. }

And my application loads the extensions like so:
Java Syntax (Toggle Plain Text)
  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!
Similar Threads
Reputation Points: 20
Solved Threads: 6
Junior Poster in Training
Cudmore is offline Offline
74 posts
since Nov 2005
Jun 11th, 2006
0

An Example that works

Here's an example I wrote that works, but it's primitive.

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

Tester.java
Java Syntax (Toggle Plain Text)
  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:
Java Syntax (Toggle Plain Text)
  1. Class Name: TestClass
  2. Press any key to continue...
Reputation Points: 20
Solved Threads: 6
Junior Poster in Training
Cudmore is offline Offline
74 posts
since Nov 2005
Jun 12th, 2006
0

Re: Making apps with future extensions

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.
Team Colleague
Reputation Points: 1658
Solved Threads: 331
duckman
jwenting is offline Offline
7,719 posts
since Nov 2004
Jun 19th, 2006
0

I figured it outttttt!!

: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:
Java Syntax (Toggle Plain Text)
  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
Java Syntax (Toggle Plain Text)
  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:
Java Syntax (Toggle Plain Text)
  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.
Reputation Points: 20
Solved Threads: 6
Junior Poster in Training
Cudmore is offline Offline
74 posts
since Nov 2005
Jun 19th, 2006
0

Re: Making apps with future extensions

It won't let me edit my previous post, so..

Incase anyone noticed in my code, in the main function I said...
Java Syntax (Toggle Plain Text)
  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.
Reputation Points: 20
Solved Threads: 6
Junior Poster in Training
Cudmore is offline Offline
74 posts
since Nov 2005
Jun 19th, 2006
0

Re: Making apps with future extensions

................................................. (Delete this -- Accident Post) .................................................
Last edited by Cudmore; Jun 19th, 2006 at 5:59 pm.
Reputation Points: 20
Solved Threads: 6
Junior Poster in Training
Cudmore is offline Offline
74 posts
since Nov 2005
Jul 22nd, 2006
0

Re: Making apps with future extensions

Quote 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.
Reputation Points: 11
Solved Threads: 0
Newbie Poster
Rotak is offline Offline
19 posts
since May 2005

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in Java Forum Timeline: Java Question - Can anyone help?
Next Thread in Java Forum Timeline: Could you help me?





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC