3.3. Easily extending OLAT

OLAT provides a extension mechanism similar to eclipse's plugin mechanism. It is of course never that advanced, but serves as the main purpose to allow developers to extend OLAT without touching the original source code

3.3.1. Extend OLAT using Eclipse

If you like to develop some extensions or just play with the sourcode and debug some workflows of a running OLAT you will need to run OLAT out of the Eclipse IDE. You can download the great Eclipse IDE including the necessary web tool plugins here

A step by step guide on how to set up Eclipse with OLAT can be found here.

3.3.2. The extension concept

To extend OLAT, you add one line in the olat_extensions.xml file pointing to your extension, and place your extension.jar file in the WEB-INF/lib directory. For starters, see the package ch.goodsolutions.demoextension in the normal OLAT source code distribution.

3.3.2.1. Extension points

The following extension points are definded so far (see table below). There is an detail step by step example that includes the ActionExtension. The ch.goodsolutions.demoextension shows the usage of the SitesCreator extension element.

Table 3.1. Extension points

Extension interfaceExtension pointClasses applying the extensionDescription

org.olat.extensions.globalmapper

MapperProvider

org.olat.dispatcher.DispatcherActionorg.olat.dispatcher.DispatcherActionthe extension can obtain a Mapper and get to know the path it is associated with
org.olat.extensions.action.ActionExtensionorg.olat.home.HomeMainController...the extension can provide a link with a text and a description and define the action that happens when the link is clicked
org.olat.extensions.css.CSSIncluderorg.olat.gui.components.Windoworg.olat.gui.css.CSSGeneratorthe extension can provide a path (which it owns by using a Mapper extension where its stylesheet resides that should be included in every OLAT main window. Since all CSS definitions from all extensions share the same name space, it is useful to prefix the css classes with some short name of the extension. CSS class definitions should not start with "o_" since that prefix is used for the OLAT base system
org.olat.extensions.hibernate.HibernateConfiguratororg.olat.persistence.DBorg.olat.persistence.DBthe extension can add additional hibernate mappings here. Keep in mind that creating tables is quite difficult to do here. So this needs a separate sql script in the database dialect you are using. Any suggestions for a cool solution here are greatly welcomed!
org.olat.extensions.sitescreator.SitesCreatororg.olat.gui.control.generic.dtabs.DTabsorg.olat.FullChiefControllerif the extension wants to add one or more new sites (like "Home", "Groups", "Learning resources"), then a SitesCreator needs to be offered by the extension which in turn must return a list of SiteDefinition objects, each of which is responsible to create a SiteInstance.


3.3.3. How to add a new site

In short: write your new code (see ch.goodsolutions.demoextension), deploy the code as a jar, add a line in the olat_extensions.xml, restart olat.

3.3.3.1. How to create a new workflow in OLAT

This section will cover the task how to implement a new workflow or change an existing workflows that starts with an user request (e.g. clicking a link in the browser gui or submitting a form with the browser). There are two ways to extend the functionallity in OLAT. First use the extension mechanism. A good example for the extension mechanism is the ch.goodsolutions.demoextension (To enable it uncomment the demoextension in the webapp/WEB-INF/olat-extension.xml and you will get a new tab in the main navigation called "demo-site"). The advantage of extensions is that they can be deployed as a single jar file containing all resources they need (properties files, translation files, images and classes). The other possibility to extend OLAT is to modify existing workflows. The main differeces between the two ways are that the resources of the existing stuff is spread in several locations and loaded automatically upon a request. Resources of existing workflows are located at:

classes  --> YOURPACKAGENAME/yourclass.java
content (velocity templates) --> YOURPACKAGENAME/_content/yourcontent.html
css files (static content) --> YOURPACKAGENAME/_static/css/yourcss.css
image files (static content) --> YOURPACKAGENAME/_static/css/img/yourimage.png
js files (static content) --> YOURPACKAGENAME/_static/js/yourjs.js
translations (properties) --> YOURPACKAGENAME/_i18n/LocalStrings_en.properties

The resources of content and translations are automatically reloaded if you switched off caching of velocity pages in the build.properties file (velocity.cache.pages=false) and the language files (localization.cache=false). This is handy during development as the changes show up without restarting tomcat. Therefore is might be faster to develop your extension with your files in the different locations above and if you finished work move it to an extension directory where all staff is bundled and can get exported into a jar. We will first cover adding new content without the extension mechanism and later put the stuff into an extension.

Basically the following steps are necessary to create a new site with interaction in OLAT. Create a class that inherits from the BasicController class. By overriding the event methods you can listen to you events like your buttons or your created links and react according to the event. The controller class works together with a template file you specitfy as VelocityContainer you created. See the index.html file in the demo extension or any other template file under PAKCAGENAME/_content as guide to your content. The special variable "$r" gives you access to the framework methods for rendering componets ($r.render("myLink")) and variables created in your controller ($variableName).The class VelocityRenderDecorator gives you a list of methods that can be used in all velocity pages.

We will now go through all steps in detail for a simple example (The famous Hello world example!) with a link that changes to your username instead of "world" and shows an image after clicking. You will find this example in the source code of olat with all needed resources: search for org.olat.test in the source.

  • Go to the sourcedirectory org.olat.test and create a new class that extends from BasicController. We did this for you and named the class HelloWorldController.java. See the comments inside the class that give you helpful hints about the code. You have now a Controller class that listens to a template page. The HTML page (container) it listens to is specified as class var in the top of the class.

    myContent = createVelocityContainer("helloworld");
           

    The "helloworld.html file" you have to create in YOURPACKAGE/_content folder. And will be resolved as helloworld.html This file contains HTML and Velocity template code (For a reference of the Velocity template language see: VTL reference ). Inside the velocity template you can reference variables from your java class and also complete other components from other controllers. See for example:

    myContent.contextPut("myContentVariable", myString );
           

    The variable "myContentVariable" is accessible it the "helloworld.html" by typing "$myContentVariable" (without the capitals!)

  • Now we cover the PackageTranslator (translator) object which got automatically created for our controller. It is responsible for translating the content to the language the logged in user choosed. The translator looks for an other file that you have to create in YOURPACKAGE/_i18n. You can access it everywhere in your controller by calling getTranslator().translate("yourKey") LocalStrings_en.properties . This are java properties files where you can specify "key = value" pairs for the string you like to have translated.

  • You should now have all needed stuff: A controller class where you listen to your action. A velocity page that produces HTML output and a LocaleStrings_**.properties file for each language.

  • As there is no direct URL that you could enter in the browser to access you newly created content we have to "enable" it somewhere else. Excursus: OLAT URL's explained. Each link in OLAT is unique and gets dynamically generated for every page. The URL's contain the dynamically added component id and also an timestamp that gets incrementet with each click. So every OLAT URL is only valid once. This makes development of applications much easier as you do not have to worry about actions sended twice.

  • For testing purposes we add our content in the testing tab of the main navigation. To turn on this tab enable it in by uncommenting it in the "olat-extension.xml" file and restart OLAT. Make sure you also enabled the OLAT debug mode in the build.properties file. You find the olat-extensions.xml file under /webapp/WEB-INF/olat-extensions.xml. You should now see the tab "testing" and a menu (left) with several links to teststuff. You also see a link named "Hello World". Clicking this link will create our controller and show our content in the content area of OLAT. But how do I add a link to this menu?

    Sure, we have to find the appropriate controller and add a link there and listen to the event the link produces and create our own controller. More or less the same we did in the HelloWorldController. But first we need to find the right controller out of many. There is a handy feature in the debug mode of OLAT that helps in this case. In the OLAT footer you will find a link called "Debug rendering: maxi, mini, off". Switch on render debug in the mini mode and you can hover over the content to get usefull information about each component. Hover over the leftside menu top title and a layer will appear. Look for listener and you will find org.olat.test.TestingMainController. This controller listens to the links in the left side menu. This mean that this is the right place to add our "Hello World" link.

  • If you open TestingMainController you will see that it consists off the same structure as our own controller. It has an constructor where translator object gets created and also an velocity container. You will find also an event method that listens for events to this controller. See inside the source and you will find the place where the link is added to the menu tree and where the event is handeld.

3.3.3.2. How to export the extension

Simply pack your olat extension project into a jar file (e.g. in Eclipse File-Export-JarFile)

To change our "Hello World" example into an extension that can be deployed as a singe jar to following steps are necessary:

  • Create file structure

    xy.test.demoextension
     controller
     _content
     _i18n
     _static
     HelloWorldExtension.java
          
  • Copy files to folders. The HelloWorldController to the controller folder and the properties files to the _i18n folder. Make sure you rename the "LocalStrings.properties" files to "LocalStrings_xy.properties" where "xy" stands for the country code like "en" for english as they are now all in the same folder. The images and optional css (Stylesheet) files belong to the _static folder.

  • Let's now create the Extension class. The extension class is responsible for creating an instance of our HelloWorldController and also to provide a visible link in the layout. Every Extenstion has therefor to implement the Extension interface. The only interface method "getExtensionFor()" is looking in a Hashmap for our extension that is is registered in the olat_extension.xml file. See below for an example. To add our extension to the ExtensionElements we have to add it first. We create a ExtensionElements object, that holds only objects of type ExtensionElement (see the table Section 3.3.2.1, “Extension points” at the beginning of the chapter for a list of the know ExtensionElement's). The HelloWorldExtension uses the ExtensionPoint ActionExtension which adds a link to the menu in the user "Home". The ActionExtension in our example is done with an inner class for brevity.

  • The only thing left is to export the extension as a jar file put it in the olat lib directory and enable your extension in the global olat_extension.xml file (see below) and restart olat and your done! If you consider sharing your extension with the OLAT community send your jar to the developer mailinglist and we will include it in OLAT or provide a download link on www.olat.org. Your help is very welcome and do not hesitate sending us your extension or ask questions on how to create one!

3.3.3.3. How to deploy the extension

Consider the file olat_extensions.xml in the WEB-INF directory. Add your bean to the olat extensions by adding a line where the comments says to add. The class attribute must point to your class which implements the Extension interface.


 <!-- generic OLAT extensions -->
 <bean id="extmanager" class="org.olat.extensions.ExtManager" singleton="true">
  <property name="extensions">
   <list>
    <!-- classes implementing the Extension interface -->
    <!-- add your extensions here! -->
    <bean id="demoextension" class="ch.goodsolutions.demoextension.DemoExtension" singleton="true" />
   </list>
  </property>
 </bean>