[MUD-Dev] Extensibility

Kwon Ekstrom justice at softhome.net
Tue May 7 00:53:30 New Zealand Standard Time 2002


From: "Ben Chambers" <bjchamb at bellsouth.net>

> Is it possible to use the ability of Java to dynamically load
> classes to make it easier to add new features to your MUD without
> recompiling?  I was thinking that instead of having code snippet
> archives it would be cool if there was some source of expandable
> Java classes.  You know, if you want this new feature, simply
> download this .class file and load it into the server using the
> graphical front end.  Then simply reboot the server (this might not
> be necessary) and without recompiling or anything you have updated
> your server.

That's quite simple, just pass the classloader the fully qualified
class name. and it'll load the class for you.

Give the class a static initializier to pop it into all the right
spots and there you have it.

I similar code to init modules in my server:

  public void initModule(String ch) {
    try {
        Class.forName(ch);
    } catch(Exception e) {
        e.printStackTrace();
    }
  }

Then I'd have a static initializer to handle things as:

  class dummyModule {
    static {
        AaernMU aaern = AaernMU.get();
        aaern.addHandler(new dummyHandler());
    }
  }

A few explainations, my server uses a singleton to reference the
current server.  I have a list of handlers which implement a Handler
interface which defines a simple public void handle() method.

Class.forName throws 3 exceptions, ClassNotFoundException,
LinkageError, and ExceptionInInitializerError.  I don't care what
gets throw, if an error occurs I know I can't load the class, simple
as that.

Static initialiers run as soon as the class is loaded into
memory... an error in your initialization code will cause the class
loader to throw an ExceptionInInitializerError.  You can do anything
you want here... For example alot of my classes use a static
initializer to read in data files, and setup your initial state.

Each game cycle the main loop gets each handler, and calls it's
handler method.

There's alot more to it, I use an event/listener system, so you can
simply attach listeners to various objects to do more complex
handling.  Almost every aspect of my server is loaded like that.

Command functions are objects, and I load them with the class name,
then check if the class is an instance of doFunct.  I can write
commands and load them on the fly... the only problem is it's a pain
to unload a class to load it again.  So modifying a class that's
already loaded requires a reboot.  Another advantage of using
objects for command functions is that I can put fields on them and
save them to the output file.  This allows me to define alot of the
behavior of commands online (and thus allowing someone else to
handle the tweaking...).  Several of the messages are handled in
this way.

An easy way to handle reading in modules could be:

  import java.io.FileInputStream;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.io.FileNotFoundException;
  import java.io.EOFException;
  
  public class ModuleReader {
      public void read(String file) {
          try {
              FileInputStream f = new FileInputStream(file);
              BufferedReader in = new BufferedReader(new
  InputStreamReader(f));
  
              while(true)
                  initModule(in.readLine());
              return;
          } catch(FileNotFoundException e) {
              System.out.println("Unable to find file "+file);
          } catch(EOFException e) {
          } catch(NullPointerException e) {
          } catch(Exception e) {
              System.out.println("Error reading from stream.");
              e.printStackTrace();
          }
      }
  
      public void initModule(String ch) {
          try {
              Class.forName(ch);
          } catch(Exception e) {
              e.printStackTrace();
          }
      }
  }
  
You'll probably want to put in some checks in the while loop to make
sure that data is available, it should throw an exception when it
reaches the end of the stream.  I've found that sockets throw a
NullPointerException, which is why I catch it.

With a few minor modifications, that code should allow you to
dynamically load classes using a file with line delimited class
names.  If you're reading files in a jar, then you'll have to make a
few modifications.

-- Kwon J. Ekstrom
_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://www.kanga.nu/lists/listinfo/mud-dev



More information about the MUD-Dev mailing list