Component Framework

Abstract

This document describes the MMBase component framework.


The component framework adds component based development to MMBase. To start appreciating component based development, lets turn to an example of integrating a poll component into your website. In the MMBase releases prior to 1.9, you had to include the poll.jsp into your jsp page. The most difficult part was that you had to change the url generated by the poll such that the answer provided by the user was posted to the right page. Moreover, the url also had to contain all other necessary information needed for other functionality on that same page. You also had to change the layout of poll.jsp so that the layout fits the layout of your website. By using the component framework the poll component can be integrated without the need to make a change to the component itself. The information to post the answer of the user to the right page is taken care of by the component framework and the layout of the poll follows the layout of the website automatically by means of the default css classes.

Standardisation of the way components interact with one another is another advantage of component based development. For instance you might want the votes on the poll to be registered in the users profile of the community component. In MMBase releases prior to 1.9 you had to "hardcode" the presence of the community component in your website. Within the component framework the poll component can simply ask whether the community component is present. More general in the component framework, components are aware of eachother presence and can respond to each others events. (TODO: is this already implemented ??)

Of course if it is only a poll that has to be integrated, the overhead of using component based development is much larger than the gain from reusing the component without any change. However most component for instance in Didactor consists of 50+ templates. Imagine what it would mean if you could reuse such a component without the need to review and change all of these templates.

Components can be accessed from jsp-pages directly or be used in a portlet engine / portal service. For use in jsp-pages MMBase offers tags in the MMBase taglibrary which put the components into action and render their content into the pages of a website. When using a portlet engine and portal service, like the CMS Container, this engine takes care of analyzing the client request, make the selected portlets execute, render their content and return the resulting page to the client.

The MMBase Component Frameworks adds a new directory to MMBase's configuration. This directory is specified in the mmbaseroot.xml and by default is: '/WEB-INF/config/components'. Note however that after installing MMBase you will not find any files here, because the default config files are stored inside the mmbase.jar.

The core of a component is the component.xml. It specifies the blocks in the component and the renderes within each block. The following example provides the ecards.xml for an ecard component.

<?xml version="1.0" encoding="UTF-8"?>
<component
    name="ecards"
    defaultblock="home"
    xmlns="http://www.mmbase.org/xmlns/component"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.mmbase.org/xmlns/component
                        http://www.mmbase.org/xmlns/component.xsd">
  <description>Ecards component</description>
  <block name="home" mimetype="text/html">
    <process jsp="ecards_init.jsp" />
    <head jsp="ecards_head.jsp" />
    <body jsp="ecards.jsp" />
  </block>
  <block name="select" mimetype="text/html">
    <head jsp="ecards_head.jsp" />
    <body jsp="ecards_selectecard.jsp" />
  </block>
  <block name="done" mimetype="text/html">
    <process class="org.mmbase.ecards.Send" />
    <head jsp="ecards_head.jsp" />
    <body jsp="ecards_done.jsp" />
  </block>
</component>

In the above example most renderes are jsp-includes. It is also possible to use java classes as renderer, for example <process class="org.mmbase.ecards.Send" />.

The information available to the jsp files are the request parameters, session attributes and the ids and jspvars put into the scope by tags in which the <mm:content /> tag is contained (see also section 4.5 on parameters). For the java classes the information is available from HttpServletRequest request and HttpServletResponse response. Btw. by using request.getSession() the session in which the block is rendered can be accessed.

This section provides an overview over the parameters and functionality of the <mm:content /> tag.

The renderes that are supported in the present implementation are: head, body, and process.

The process renderer of block is called implicitly, if the head or the body of that block is called. The process renderer of block will only be executed once per calling page. To give an example: if your page contains two polls, the processor of only one of these polls will be carried out after voting. (Which seems to be a defendable assumption in this epoch of single-moused computers) The process render does not produce any output.

The renderer for body with mimetype="text/html" by convention should render a <div /> with class="mm_c mm_c_<component name> mm_c_b_<block name> ${requestScope.className}". The framework will assign a value to request attribute ${requestScope.componentClassName} . For example a framework could render the poll component within the div <class="mm_c mm_c_ecard mm_c_b_home left">. The basic implementation of the MMBase framework does not implement ${requestScope.className}, leaving the last part of the class definition empty.

The framework also renders an unique id for the <div /> containing a component. To summarize each renderer should contain:

<div
    class="mm_c mm_c_ecard mm_c_b_home ${requestScope.componentClassName}"
    id="${requestScope.componentId}"
>

In future the class specification should be extended with classes for icons and content images, which would give graphical designers also global control over what happens with icons and content images in a page (see

On default when no renderer is specified the render 'body' will be returned. If there is no body renderer defined in the component the first renderer specified in the component will be used as the default renderer. This could for instance be handy when you implement a component that only need to be rendered in the head of a page.

Next to basic reference implementation of the component framework included in the MMBase core other frameworks exist, for instance the CMS Container and Patmos. Each framework is providing the context in which components are rendered. This is done by changing the behavior of the <mm:url /> and the <mm:include /> tag. The next section shows how frameworks are implemented. The "Hello Again!" example gives an example of using a framework.

The use of the Framework functionality is shown by the following "Hello again!" example.

<?xml version="1.0" encoding="UTF-8"?>
<component
    xmlns="http://www.mmbase.org/xmlns/component"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.mmbase.org/xmlns/component http://www.mmbase.org/xmlns/component.xsd"
    name="helloworld">
  <description>Hello Again</description>
  <block name="home" mimetype="text/html">
    <head jsp="hello_head.jsp" />
  </block>
</component>

The jsp-include hello_head looks like:

<%@page language="java" contentType="text/html;charset=utf-8" session="false"%>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-1.0" prefix="mm"%>
<mm:content type="text/html" language="en">
<mm:cloud>
   <title>Hello world</title>
   <link rel="stylesheet" type="text/css" href="<mm:url page="css/hello.css" component="hello" />" />
</mm:cloud>
</mm:content>

The jsp-page that uses this component looks like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<%@page import="org.mmbase.framework.*"%>
<%@page import="org.mmbase.util.functions.*"%>
<%@page language="java" contentType="text/html;charset=utf-8" session="false"%>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-1.0" prefix="mm"%>
<mm:content type="text/html" language="en">
<mm:cloud>
<mm:import externid="component" />
<head>
   <!-- parameters are case sensitive ->
   <mm:component name="hello" block="home" render="head" />
</head>
<body>
   <h1>Hello again!</h1>
</body>
</mm:cloud>
</mm:content>

The call to <mm:url page="css/hello.css" component="hello" /> is picked up by the getUrl() method of the framework which is specified for this MMBase instance.

This method

getUrl(String page, String component, Cloud cloud, PageContext pageContext, List params)

could for instance call

UrlResolver.findUrl(component + "/" + page, cloud, pageContext, params)

In the findUrl() method the params can be used to select different css-es for different portals. The code which is used for this looks something like:

Node portalNode = cloud.getNode((String)params.get("portal"));
String finalpage = findUrl(page, portalNode, mapNode);
if (finalpage != null) {
   return File.separator + finalpage;
}

The example framework presented here thus provides the functionality to use one set of templates, but have subsites with different layouts and subsite-specific includes.

To give an idea of how a portlet engine / portal service works this sections gives an overview of the flow of actions that take place when a client calls an url:

  1. Client calls url

  2. Tomcat (or other application server) routes url to web application of the portal

  3. A servlet inside the portal web application receives the url

  4. Portal servlet will analyze the request

  5. Start of action phase

  6. Start of render phase

In the above flow no separation is made between portal service and the portlet engine (for instance pluto). The portlet engine provides the runtime environment for the portlet instances. The portal service does all page related stuff.

It is handy to use the same structure to store the files of a component within an application or contribution. When it comes to building, the exact location is of minor importance because the build process can reshuffle directories to get them into the right location in the build. Below follows an overview of how files are structured at the moment.


This is part of the MMBase documentation.

For questions and remarks about this documentation mail to: [email protected]