Software/jModuleLoader/Documentation

From TomJudge.com
Jump to: navigation, search
Navigation

Contents

jModuleLoader - Documentation

There are 2 types of module that jModuleLoader is capable of loading: those that have a specific generic interface (otherwise known within jModuleLoader as the loading interface) to the modules code and those that do not. Before developing an application with jModuleLoader I suggest that you read up on java class loaders.

I shall now go though a short example on creating both a interface based loading system and an anonymous loading system.

Modules with a loading interface

This form of module is very useful for adding plug-in support to an existing application or creating applications that are mainly module oriented. The Loading Interface

The module loading interface is probably the single most important developer facing interface in jModuleLoader. This is because once you have asked the module loader to load a module all you are given is a loading interface to the code in the module. This system was developed to make jModuleLoader a very flexible module loading solution. jModuleLoader comes with a very simple loading interface for zero parameter constructor classes (e.g. ModX x = new ModX();).

In order for jModuleLoader to be useful in most situations the developer (you) is going to have to extend the module loading interface to allow the application to access the module and the module to access the application. A typical loading interface for a modular gui application would look like the following:

public interface LoadingInterface extends com.tomjudge.jmoduleloader.ModuleLoadingInterface {
	public javax.swing.ImageIcon getWindowIcon();
	public String getWindowText();
	public javax.swing.JPanel getPanel();
}

Of course it is possible to define much more complex module <--> application interaction using custom interfaces and classes use as message passing interfaces, but I can't detail every possible solution so I leave it up to your imagination. For some ideas see the links page. The next task is to customize the module loader to make use of you new loading interface.


Customizing the Module Loader

Using the module loader is as simple as passing it the location of the module jar file as a string. However if you want to anything with the code that you have loaded then you are going to need to extend the module loader (To this extent com.tomjudge.jmoduleloader.ModuleLoader is an abstract class therefore forcing you to extend it).

The following example shows how the above interface can be used to create a new window for every module that is loaded.

import com.tomjudge.jmoduleloader.ModuleLoader;
import com.tomjudge.jmoduleloader.ModuleLoadingInterface;
import com.tomjudge.jmoduleloader.ModuleLoadingException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
 
public class Loader extends ModuleLoader {
	public Loader() {
		super();
	}
 
	protected void postLoad(ModuleLoadingInterface module, 
			URL location) throws ModuleLoadingException {
		System.out.println("Loading Interface: "+module.getClass().getName());
		LoadingInterface loadingIterface = (LoadingInterface)module;
		final JFrame frame = new JFrame(loadingInterface.getWindowText));
		frame.setIconImage(loadingInterface.getWindowIcon().getImage());
		frame.setLayout(new java.awt.BorderLayout());
		frame.add(loadingInterface.getPanel(), BorderLayout.CENTER);
		SwingUtilities.invokeAndWait(new Runnable() {
			public void run() {
				frame.setVisable(true);
			}
		});
    	}
}

Now you have a module loading interface and a module loader you need a module.

A quick introduction to modules

There is one problem with developing dynamically loaded modules that might throw you off when getting started. When you are developing you modules it is very important that you develop your module loader and your module in different working directories and compile them to different directories. This is very important because if the code you are trying to load as a module accidentally finds its way into the runtime environments class path you will find that the code starts to experience security violations because the wrong class loaders are being used to access the classes. The following directory structure is a basic recommendation for developers who are not working in some form of IDE.

application/
	src/
	build/
	dist/
module/
	src/
	build/
	dist/

By using this structure and not placing the module directories into the class path you should avoid any security violations.

Your first module

Modules do not need to only consist of a single class but to make this example simpler I shall only be showing a single class example.

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JButton;
 
public class Module implemements LoadingInterface {
	public ImageIcon getWindowIcon() {
		return new ImageIcon(this.getClass().getResource("image.png"));
	}
	public String getWindowText() {
		return "Test Module Title";
	}
 
	public JPanel getPanel() {
		JPanel ret = new JPanel(new java.awt.BorderLayout());
		ret.add(new JButton("Test Button"), java.awt.BorderLayout.CENTER);
		return ret;
	}
}

The Loading Descriptor

Now that we have the module, we need to describe it to the module loader so that it can successfully load the module. The module descriptor takes the form of a XML document called jmodule.xml, which needs to be placed in the META-INF directory in the jar file. Unfortunately due to a limitation that I have yet to find a way round the DTD must be included in top of the document.

The first 2 fields in the descriptor are fairly simple but the last (interface) is a little more complex. The interface field should contain the fully qualified class name of the module loading interface implementation.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jModule [
	<!ELEMENT jModule (title, description?, interface?)>
	<!ELEMENT title (#PCDATA)>
	<!ELEMENT description (#PCDATA)>
	<!ELEMENT interface (#PCDATA)>
]>
<jModule>
	<title>Test Module</title>
	<description>Module Loader Testing File</description>
	<interface>Module</interface>
</jModule>

Packaging it all up

Your almost there you have the module and you have the loading description, you have the loader. The last thing you have to do before you load the module is to package it up ready for loading. I will describe 2 of the most common options available to do this.

Using the command line

Using the command line jar tool distributed with your JDK the following command executed from the module directory in the above directory structure will create a jar file called module.jar in the dist directory.

jar cvf dist/module.jar -c src *

Using ant

The other commonly used option would be to use the Apache foundations ant build system. The following build file placed in module directory will compile and build a module jar file.

<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="dist" name="demo">
 
    <property name="src" location="src"/>
    <property name="build" location="build"/>
    <property name="dist" location="dist"/>
    <property name="app" location="../build"/>
 
    <target name="init">
        <tstamp/>
    </target>
 
    <target name="compile" depends="init">
        <javac
		debug="true"
		deprecation="true"
		classpath="${app}"
		destdir="${build}"
		srcdir="${src}"
	/>
    </target>
 
    <target name="dist" depends="compile">
 
        <mkdir dir="${dist}/module"/>
        <mkdir dir="${dist}/module/META-INF"/>
        <copy file="${src}/META-INF/jmodule.xml" todir="${dist}/module/META-INF" />
 
        <copy todir="${dist}/module">
            <fileset dir="${build}"/>
        </copy>
        <jar destfile="${dist}/module.jar" basedir="${dist}/module"/>
 
        <delete dir="${dist}/module"/>
    </target>
</project>

Loading the module

Your finally there you are now ready to load your first module the following simple code will load the module.

public class Test {
	public static void main(String[] args) {
		Loader loader = new Loader();
		loader.loadModule("/path/to/module.jar");
	}
}

Modules without a loading interface

The second type of module are those without loading interfaces. Obviously this type of module does not need a loading interface. The only things that need doing are customizing the module loader, and writing the loading descriptor. The later steps from packaging the module are the same as those for the modules with loading interfaces. Customizing the module loader

Modules without when the module loader calls the post load function while loading a module with no loading interface the loading interface parameter is set as null. This small example shows how to load resources from a jar file.

import com.tomjudge.jmoduleloader.ModuleLoader;
import com.tomjudge.jmoduleloader.ModuleLoadingInterface;
import com.tomjudge.jmoduleloader.ModuleLoadingException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
 
public class Loader extends ModuleLoader {
	public Loader() {
		super();
	}
 
	protected void postLoad(ModuleLoadingInterface module, 
			URL location) throws ModuleLoadingException {
		final JFrame frame = new JFrame("Test Frame");
		IconImage image = new IconImage(this.getClass().getResource("/image.png"));
		frame.setIconImage(image);
		frame.setLayout(new java.awt.BorderLayout());
		SwingUtilities.invokeAndWait(new Runnable() {
			public void run() {
				frame.setVisable(true);
			}
		});
    	}
}

The loading descriptor

The following is an example of a module descriptor for a module without a loading interface.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jModule [
	<!ELEMENT jModule (title, description?, interface?)>
	<!ELEMENT title (#PCDATA)>
	<!ELEMENT description (#PCDATA)>
	<!ELEMENT interface (#PCDATA)>
]>
<jModule>
	<title>Test Module</title>
	<description>Module Loader Testing File</description>
</jModule>
Personal tools