-
Notifications
You must be signed in to change notification settings - Fork 0
Lessons jar
Teachers need to be given the ability to change the exercices presented to their pupils. Doing so requires for now to modify the main jar file, which is a bit cumbersome. This is still possible (as detailed in next section), but it would be better if the lessons could be loaded separately from (hopefuly simple) archive files. This page aims both at providing documention to teachers wanting to edit their lessons, and discuss the implementation of this mecanism.
This section details a (crude) method to edit the existing lesson. It does not allow to change the code of the exercices, but only to change the mission texts. Do so if you just want to adapt these text to your pupils. Here are the steps to follow for that:
- Open the .jar archive in a specific directory (you need to take at least version 20120319 of JLM);
- Modify the pages you want to change (see below);
- Reconstruct the jar file by typing the following from the directory in which you opened the archive. “jar -cfe ../jlm-personnal-version.jar jlm/core/ui/JavaLearningMachine .” (don’t forget the ending dot) It creates an archive called ../jlm-personnal-version.jar with your own content. Of course you can pick your own name.
The files you want to edit are the various .html spread under the lessons/ path. In particular, lessons/chooser/LessonChooser.html is the default opening page when the JLM starts. Note that if your environment is configured to use French instead of English, the file lessons/chooser/LessonChooser.fr.html is used instead. If you want to use French by default and still maintain only one file, simply rename lessons/chooser/LessonChooser.fr.html into lessons/chooser/LessonChooser.html and edit that file directly. It won’t be possible to see your lesson in english, but you may not care.
These files are almost classical HTML files, so you can use all the classical tags <h12345> for headers, <b> for bold, <i> for italics and so on. The main specificity concerns the links. You can add links (using the classical <a> tag) to jlm://TheLesson/TheExercise When the pupils click on such links, it automatically switch the interface to the specified exercice. If you omit the exercice, the first exercice of the lesson is used. The lessons’ names are the package names (such as lessons.welcome) while the exercices’ names are the class names (such as BDR2).
Example: <a href=“jlm://lessons.welcome/BDR2”>Switch directly to the BDR2 exercise of lesson welcome</a>
→ See the How to ship a lesson page for the implemented structure
For now, all JLM’s lessons are stored in the src.lessons package. When starting, JLM loads a specific lesson from the lessons.chooser package. It constitutes the front page linking to all the other lessons available. We envision to add a specific link to this page requesting to load a new lesson from a separate archive file when this feature is implemented.
This external file will probably be a regular JAR file, with the following content:
- The META-INF folder generated in any JAR. In particular, it should contain a specific attribute specifying the path to the lesson that can be found in the archive. This would be very similar to the Main-Class attribute that allows the JVM to select the class from which the main(String[] args) method will be used.
- A lesson package named e.g. “top_2012”. This name must be unique amongst all existing lessons because that name is used in the path to the data saved on pupils’ machine.
- Then, the lessons packaged as JAR file would have the same structure than any other lesson. Even the chooser shares this structure.
- Main.java instantiates the class Lesson. The only method is loadExercises(), in charge of calling the constructor of each Exercise or Lecture (an exercise were no question is asked to the students), and declaring the graph of dependencies between the exercises (used to construct the graph of the dependencies).
- Main.html file, describing the lesson in the “About this lesson” help menu.
- Optionally Main.locale.html, being the translation of the file above (locale in the short version, e.g. Main.fr.html ). The localized file corresponding to the settings of the user machine is used in priority if it exists ( Main.de.html would be used by german-speaking users if existing).
- Other resources (such as images and icons) can be added too, and referred to from the html files.
- Finally, the lesson contains a set of exercices, all sharing the same organization too. This organization is detailed here How-to-add-an-exercise (link to the page on main trunk in case this very project fork is not synched yet https://github.com/oster/JLM/wiki/How-to-add-an-exercise).
In the end, it turns out that using Reflection to directly access the “addURL” method of the system classloader through Reflection is a working solution. It’s ugly but works, assuming that the system classloader is actually an URLClassLoader (which seems to be usually the case). Also, it bypasses the Java protection of visibility, since the addURL method is a protected method.
The JLMClassLoader is now responsible for adding a JAR to the URLClassLoader classpath at runtime, doing so, keeping an internal list of loaded JARs. After adding the JAR, it also loads the lesson contained in it, getting the package name from the Manifest file (How to ship a lesson).
Previous research:
Loading a JAR into a running Java program requires to define a custom ClassLoader, as the default ClassLoader doesn’t allow to load new “classes locations” (here, a JAR) at runtime.
→ http://stackoverflow.com/questions/194698/how-to-load-a-jar-file-at-runtime
An URLClassLoader would allow to add a JAR into the program at runtime.
Digging into the current code reveals that implementing such a loader might be troublesome, as the classes, the html and probably the other resources files aren’t loaded in the same place, nor in the same way.
Options considered at this point:
* Defining the custom ClassLoader as being the general/default loader for the entire JLM, adding the ability to load a JAR at runtime on top of loading all the other classes.
* Having the custom ClassLoader defined somewhere, to be used only when loading a JAR, alongside the default ClassLoader. This approach is risky, as the calls to the class loader aren’t documented in the existing code, and might not be fully identified.
** Calls to the class loader currently spotted:
(Game.java:93) lesson = (Lesson) Class.forName(lessonName + ".Main").newInstance();
(Reader.java:71) InputStream s = ExerciseTemplated.class.getResourceAsStream(resourceName);
Custom classloader:
- http://techblug.wordpress.com/2012/03/17/classloader-tips/
- http://www.velocityreviews.com/forums/t517526-jars-inside-a-jar-custom-classloader.html
- http://blog.cyberborean.org/2007/07/04/custom-classloaders-the-black-art-of-java
- http://www.javablogging.com/java-classloader-4-loading-a-custom-classloader-on-jvm-start/
- http://stackoverflow.com/questions/4095976/how-to-put-custom-classloader-to-use
- http://stackoverflow.com/questions/826319/classcastexception-when-casting-to-the-same-class
- http://www.coderanch.com/t/384068/java/java/Adding-JAR-file-Classpath-at
Reflection: