3.2. Application Layers

3.2.1. Responsibilities of the layers in short

3.2.1.1. Servlets deployed by OLAT

The OLATServlet is the main entry point for user requests from the browser. This servlet uses Dispatchers to further process a request. This is done by the class DispatcherAction. Furthermore, the OLATServlet is responsible for initializing and configuring OLAT. This is done by calling the ConfigurationManager at startup.

DispatcherAction analyzes the first part of the incoming request URI and decides which Dispatcher is repsponsible for further dispatching the request. These Dispatchers are namely:

  • DMZDispatcher: Responsible for all requests of users who are not yet authenticated. DMZDispatcher processess all URIs starting with /dmz/, namely the login process.

  • AuthenticatedDispatcher: Responsible for all requests of users who have been previousely authenticated. AuthenticatedDispatcher will check each incoming request if it has an authenticated user associated. If not, the user is redirected to the login screen. AuthenticatedDispatcher catches all requests starting with /auth/.

  • ShibbolethDispatcher: This Dispatcher catches all requests comming asynchronuousely from IdentityProviders. Its assigned sub-URI is "/shib/", please refer to the Shibboleth Protocol for further infos on Shibboleth.

Besides OLATServlet, there are a few more servlets used within OLAT. Find a brief description of the functionality they provide below:

  • SecureWebdavServlet: This is the servlet handling all WebDAV requests. The servlet is mapped at URI /webdav/. This URI is the same for every user. The WebDAV contents are assembled for every user after authentication.

  • StaticsServlet: This servlet is handling requests for statics such as imges or CSS and Javascript files. StaticsServlet is mapped to the sub-URI /secstatic/. This sub-URI is further followed by a handler name (i.e. /secstatic/HANDLER/. According to the handler name, SecstaticsServlet passess the request to the handler which registered for the given handler name. Handlers can be configured in olat_config.xml. A handler must implements PathHandler and an alias must be given under which requests are dispatched. See the configuration of the StaticsModule in olat_config.xml namely its Path entries for an example.

  • RSSServlet: This servlet pretty much does what it says. It provides RSS feeds for subscribers and is mapped at /rss/.

  • OLATDevServlet: This servlet is used for development purposes. It implements workflows usefuly to the development of OLAT. With this servlet, developers can edit Velocity pages on the fly by enabling debugging in the GUI. Furthermore a translation tool helps in translating OLAT to other languages. The translation tool is accessible through the administration page.

3.2.1.2. Windows / Chiefcontrollers

Each User has a UserSession which stores the windows amongst other things. The Windows contains at least one Window. A window is the server-side representation of a browser window. A window has a content-pane (like Swing) to store the "real" content. Each window is owned by a ChiefController which is responsible for the navigation the windows offers, but not for its content. So e.g. after logging in, the tabs on the top ("home", "groups", ...) are controlled by the chiefcontroller.

3.2.1.3. Controllers

A Controller is a responsible for a certain business logic / workflow

Each controller must provide an initialComponent, which is the visual representation of the controller at any given time. The component will be rendered later into a HTML fragment which is part of the whole HTML page. You could think of a Swing Panel which is embedded into some place in the webbrowser window. The code creating a controller and asking for its initialComponent can determine where to visually put the component

3.2.1.4. Managers

Managers within OLAT, by definition, are classes that implement basic services useful for implementing the actual business logic. The OLATResourceManager for instance provides the basic functionality for handling OLATResources such as creating, reading, updating and deleting. Any Controller within OLAT that has to deal with an OLATResource should use the OLATResourceManager and not directly imlement basic functionality. In particular, Managers wrap all database access.

3.2.1.5. Virtual Filesystem (VFS)

OLAT provides its own implementation of a filesystem abstraction layer, called Virtual Filesystem (VFS). The VFS represents a tree structure with folders and files within folders much like a regular filesystem. Folders are called containers and files are called leaves. There are different implementations of containers and leaves serving different purposes. These offers the flexibility to change the implementaion of the file and folder classes and may switch to an other storage solution (like database) without rewriting code in the file handling classes.

Both VFSContainer and VFSLeaf inherit from VFSItem with generic attributes and methods common to both such as a name, methods to query wether delete or write is allowed and others. The most important method defined on VFSItem is resolve(String name). This method allows to query a VFSItem to resolve a path (i.e. /home/user/readme.txt). A path is much the same as a path on a regular filesystem. Resolve() returns a VFSItem which can be either a VFSContainer or a VFSLeaf.

The second most important feature of VFSItem is its VFSSecurityCallback. A security callback defines what operations are allowed on the item. VFSSecurityCallback defines whether read/write/list/copy and delete operations are allowed. If a specific item has no VFSSecurityCallback defined, all operations are allowed by default. VFSSecurityCallbacks get inherited by all children attached to an item. So for example, if a container has a security callback set that denies write operations, the container itself and all of its children would not be writable. VFSSecurityCallback also allows to define quotas on a object. The VFSSecurityCallback is checked by the VFS implementation. I.e. if you perform a write operation, the security callback is checked and an exception is thrown if the security callback denies write opertaions on the specific item.

There are various implementations of VFSContainer and VFSLeaf already in place. The most handy probably are LocalFolderImpl and LocalFileImpl which are an abstraction of a local filesystem. These are probably the place of start for all your VFS tasks. Simply create a LocalFolderImpl with a File pointing to a local folder as constructor asgument. You can then resolve any file or folder within this local folder through the resolve() method as described above. You can create new folder or files through the respective methods of VFSContainer (createChildContainer and createChildLeaf).

A special type of implementation are all implementations based on AbstractVirtualContainer. Those will be described briefly below.

  • NamedContainerImpl : This is useful if you want a given container to show up under a different name. Note that this name will also be used to resolve the container. This works much like a symlink on a regular fielsystem.

  • MergeSource : This is a powerful but maybe a bit difficult to understand type of virtual container. It is also the reason why we chose to do our own implementation of a virtual filesystem instead of using for example Apache commons VFS. A MergeSource combines several containers or leaves into a single container. To give you an equivalent on a local filesystem, you would create a new folder, and then symlink folders or files into this folder to get the same effect. A MergeSource can merge containers in two different ways provided by two different methods. addContainer will show the given container as a child of the MergeSource. addContainersChildren will show the given container's children as children of the MergeSource. To avoid naming conflicts, only one container can be addad via addContainersChildren . Furthermore you must define whether it is allowed to write to this container. If someone wants to write to a MergeSource, this is only possible, if a container was previousely added via addContainersChildren with the write flag set to true. This feature is manly used in the WebDavProvider to show folders of different courses a user is owner in one place which makes it handy to upload files for different ressources. This folders are spread on the local filesystem and the MergeSource allow us to see them in one place.

    See

  • StreamedImpl : This is useful, if you just want to decide on the fly, what the contents of a file is. StreamedImpl simply directs its InputStream and OutputStream to whatever you provide at construction time.

With these implementations, you are quite flexible in presenting a filesystem the way you want. Note that you may also combine different implementations of VFSContainer or VFSLeaf. The WebDAV implementation in OLAT makes use of most of the features provided by VFS. At its root there is a merge source. The merge source combines VFSContainers which themselves are wrapped by NamedContainerImpls. This way, the different types of directories exposed by WebDAV can be presented in a sensible way to the user.

See javadoc of the package org.olat.core.util.vfs to get some code examples on the general usage

See VFS javadoc for more information.

3.2.1.6. Database Abstraction Layer (Hibernate)

OLAT uses the hibernate relational persistence framework to map objects to relational database tables. See the hibernate documentation to learn how to use this framework.

Every persitable class in OLAT inherits from or extends org.olat.persistence.PersistentObject . This guarantees that every class has the following common attributes:

  • private Long key = null

  • private Date creationDate

  • private Date lastModified

To make a class persistable by the hibernate layer one needs to implement getter and setter methods for every attribute added to the class; this is a hibernate convention. Getters and setters can be private if they should not be used by code outside the class.

Every class must also have an interface if it wants to use the lazy initialization options. See the hibernate documentation for more information on this. These are the naming conventions when using interfaces:

  • Interface: ClassName.java

  • Implementation: ClassNameImpl.java

Every persistable class must have a hibernate mapping description. This mapping file (an XML file) must be stored in the same package as the mapped class. See the hibernate documentation to learn how to write the mapping file. There are several strategies how to write the mapping.