Implement a module

Introduction

This section gives you an overview of the usage and implementation of Corinis-functions and modules. It describes how to implement Corinis modules basicly (we will use the guestbook-module as an example because it is quite a simple implementation). We also give a short introduction into working with XML/XSL and JSP. Basic HTML-knowledge is recommended for reading this document.

Corinis implementation - basics

Every implementation of a Corinis module follows the same schema: The module-functions where called from one or more .jsp files. JPS (Java Server Pages) are basicly normal HTML-files, but extended with special Code (quite similar to ASP). In case of a Corinis module-implementation this special code is more or less only the call of a certain function. The jsp file in a Corinis implementation therefore is more or less a normal HTML-file with a function call.

The function-call (for example: creation of a guestbook-entry, display of all entries,...) produces a result (success message, error message, list of entries,...). This result will return as a XML-tree. This XML-tree (containing the data) will now be parsed through a .xsl File to be displayed. Like every other module too, the guestbook is implemented via (at least) one .jsp and one .xsl file:

  • .jsp with the function calls
  • .xsl for displaying the guestbook

XML

Corinis CCM is XML-based. XML is a platform and system-independent form of representing data as a tree structure. Corinis uses XML to exchange data between modules, to process data from the database and to return results to the frontend (webbrowser, cellphone, ...).

XML-example (guestbook):

<GUESTBOOK>
  <ENTRY>
      <CREATE>
       <DATE>31.10.2002 02:54</DATE>
       <LDATE>123311020020254</LDATE>
       <USER>
         <NAME>asdd</NAME>
         <ID>15648432465</ID>
         <IP>127.0.0.1</IP>
        </USER>
      </CREATE>
      <MESSAGE>dddddd</MESSAGE>
    </ENTRY>
</GUESTBOOK> 

XML is a tree of raw data which looks similar to an html-snippet. Data is enclosed by tags (e.g. <NAME>) and could be access via a path (e.g. /GUESTBOOK/ENTRY/CREATE/USER/NAME). Each opening Tag (e.g. <NAME>) has to be closed again (e.g. </NAME>). In between there could be further (child-)tags therefore creating a tree structure.

Because displaying the raw-data as shown above doesn't look very nice for the user we have to use XSL or XPATH to make something nice out of it.

XSL

XSL is basicly HTML extended with some additional tags to be able to use the data of the "underlying" XML-tree (remember the XML-data is parsed through the XSL). An xsl-file contains a header, stylesheetinformation and a template-match. With the template-match we define the entrypoint - the point in the XML-tree where the XSL starts its work. Quite often this is the root element (i.g. /). The entry point is definied via:

<xsl:template match="/">
   ... HTML Code, XSL-tags,...
</xsl:template>

When using HTML in a XSL make sure that:

  • all tags have to be closed (<br> without a <br/> produces an error)
  • all attributes have to be enclosed by " (<img src=img.gif"> is wrong, <img src="img.gif"> is right)
  • Escape codes like &nbsp; are not allowed. You have to use the numeric Ansii Codes instead (&#160; instead of &nbsp;)

The simple XSL-file (completly ignoring the data from the XML) looks like this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    Hello world!
  </xsl:template>
</xsl:stylesheet>

Where and how do I find the Corinis - XSL-files

All Corinis-XSL files are stored in a defined subdirectory. The path is defined in the configuration-xml. If set to auto the xsl files reside in webroot/WEB-INF/xsl

When using xsl-files to parse xml-trees we always use relative paths to this directory - absolute paths are not allowed and will be converted to relative paths.

For the guestbook it could look like this:

<% 
//out.print(core.parseDom(gb.getEntry(), "show.xsl"));
out.print(core.parseDom(gb.getEntry(), "implementation/GuestbookgetEntry.xsl"));
%>

The first line is commented out (line starting with //). In this line "show.xsl" is used for parsing the xml-tree. This xsl is used to simply show the xml-tree as is in the browser. The second line uses the xsl-file "implementation/GuestbookgetEntry.xsl".

What to do in a XSL-file

For displaying the XML-data there are numerous xsl-functions available. For a complete list of these please refer to the numerous XML/XSL books, your designer, or us ;-) Nevertheless we want to include some of the most important xsl-functions into this documentation:

xsl:value-of

This function simply displays data out of the xml-tree.

<xsl:value-of select="/GUESTBOOK/ENTRY/CREATE/USER/NAME"/>

The attribute select defines the path to the element. This could be the absolute path (beginning with /) or a relative path (such as USER/NAME - if already in /GUESTBOOK/ENTRY/CREATE).

For example: We want to display the ID in additon to the username:

<xsl:value-of select="CREATE/USER/NAME"/> </strong><br/>
ID: <xsl:value-of select="CREATE/USER/ID"/>
</td>

xsl:for-each

This function allows to define a loop similar to one in a programming language:

Example: We want to display all Usernames (although there could be only one user who created the entry - we assume that it is possible that there are more users therefore having more <USER> entries beneath <CREATE>). Note that we are using a relative path for xsl:value-of:

<xsl:for-each select="/GUESTBOOK/ENTRY/CREATE/USER">
        <b><xsl:value-of select="NAME"/></b>
</xsl:for-each> 

xsl:if

This is a simple if-statement:

Example: We check if NAME=admin - in this case we display: The chef

<xsl:if test="NAME" = 'admin'/>
   The chef
</xsl:if>

xsl:choose

This is a complex conditional.

Example: Depending on the userid we want to display different text

<xsl:choose>
   <xsl:when test="CREATE/USER/ID=2">
       This is userid 2
   </xsl:when>
   <xsl:when test="CREATE/USER/ID=1">
       The first user
   </xsl:when>
   <xsl:otherwise>
       This is a user with a userid different to 1 or 2
   </xsl:otherwise>
</xsl:choose>

xsl:attribute

This function is used when you want to set an attributevalue to a value from the xml-tree.

Example: We want to set the title attribute to "The name is xxx" - xxx standing for the name of the user

<a href="#">
        <xsl:attribute name="title">The name is <xsl:value-of select="CREATE/USER/NAME"/></xsl:attribute>blablabla
</a>

xsl:attribute always refers to the element in which it is enclosed (in the example above <a>). This is of course not true if the enclosing element is another xsl-tag (then it is true for the enclosing element of this tag..)

another way to use attributes is with {}. Above example can be changed to:

<a href="#" title="The name is {CREATE/USER/NAME}">
        blablabla
</a>

JSP Tags or TagLib

There are multiple ways to work with Corinis. One is to use the TagLib.

To do this simply include following code in your jsps:

<%@ taglib uri="/corinisTags" prefix="corinis" %>

You can then use any available corinis-tag (see [TagLib]) in your html file. The tags will be replaced by the function code.

If you don't know what I mean look at following example:

<%@ taglib uri="/corinisTags" prefix="corinis" %>
<html>
<body>
 <h1>Hello <corinis:core name="name"/>!</h1>
</body>
</html>

This will put the name of the currently logged in user in the html:

<html>
<body>
 <h1>Hello admin!</h1>
</body>
</html>

Hello !

Most webpages can be done with these tags alone, but some functionality is not available through the taglib alone. It is a good idea to start with taglibs, since you dont have to bother with initialisation of modules or jsp/java. Also see the [HowTo/en/Implementation/CMS%20Intro Cms HowTo].

JSP

JSP stands for Java Server Pages. These are HTML-pages extended by Java-Code, which will be executed by the server before displaying the HTML-page (all quite similar to ASP). This allows you to control the HTML-output via java-code and the access to java-functions on the server. Java-code in .jsp files starts with <% and ends with %>. Everything in between is java, everything outside is normal HTML.

Using JSP with corinis gives you much more flexibility than using taglibs or only templates because you can access certain fields and functions only though java (doing things like single-sign-on with another system is only possible though java).

Including other files

Other .jsp files are includes via:

<%@include file="path/file.jsp"%>

This will take everything in path/file.jsp and put it exactly at the position where you used the include. The path/file.jsp can include any combination of HTML/JavaScript/JSP/CSS/...

Output

There are two possibilities to create output via JSP:

  • With the jsp-tag: <%= %>
    <%=core.parseDom(gb.getEntry(), "show.xsl")%> 
    
  • With the function: out.print()
    <%
    out.print(core.parseDom(gb.getEntry(), "show.xsl"));
    %> 
    

The "Java-side" of Corinis

In order to use a function of a Corinis Module there are 3 steps necessary:

  • Initialisation of the Core-server
  • Initialisation of the module
  • Call of the modulefunction(s)

These steps must be done in the above order

Initialisation of the Core-server

The Corinis Core-server or Core-module is (as the name already tells) the core of the Corinis-system. It is responsible for database- and sessionhandling as well as many basic Corinis functions. Initializing of the Core-server always looks similiar:

<%
Core core = new Core (pageContext);
%> 

Initialisation of the module

Initializing of the module follows the same scheme as the initialization of the Core-server:

ModulName variable = (ModulName)core.getModule(ModuleName.class);

For the guestbook:

Guestbook gb = (Guestbook)core.getModule(Guestbook.class);

Now the guestbook-module can be used with the variable "gb". As before we use JSP Code to initialize the module. We state the module we want to use (Be careful this is case-sensitive). The name of the varialbe (in our case gb) is upon your choice. Note that the one and only parameter for initializing a module is the already initialized Core-server (in our case the variable "core").

Call of the modulefunction

Now that we have everything initialized we can call functions of the module. Which modulefunctions are available differ from module (please see the module-documentation to find out which functions a module provides). You call a function like this:

modulevar.someFunction();
e.g. gb.getEntry();

Each function returns an XML-tree. As explained above - to be able to show this data we have to parse the returned XML-tree through a xsl-file:

<%=core.parseDom([modulevariable].[function()][, "xslfile"])%>
e.g. <%=core.parseDom(gb.getEntry(), "show.xsl")%>

The function parseDom (or parseDomHtml) of the Core-server parses the return tree through the xsl stated and displays the result. If you have implemented the function call(s) you can go on and write the xsl-files to finish implementation. As a basis you can use the output produced by the show.xsl - which simply shows the tree as it was returned.

Another way to work with the return DOM Trees is to combine them and parse the resulting tree in one step:

core.addDom(modulevariable.function());
core.addDom(modulevariable2.function());
core.parseDom("xslfile");

e.g.

core.addDom(forum.getMainEntries());
core.addDom(forum.getEntries());
core.parseDom("show.xsl");

The resulting xsl will look like this:

<corinis>
  <dom1>
     ...
  </dom1>
  <dom2>
     ...
  </dom2>
</corinis>

This way you can combine as many function returns as you want.

Creating entries

To create entries (guestbook entry, document,...) a HTML-form is necessary - this will tell the function what to do. This could be done within the .jsp or the .xsl file. We recommend to do it in the .jsp file, if possible, but this is a question about your implementation-style...

Example: Entry-create form for the guestbook

.....
<form method="post">
Name: <input name="Guestbook_username"/> <br>
<textarea name="Guestbook_message" rows="5" cols="50"></textarea><br>
<input type="submit" name="Guestbook_createEntry" value="Submit"><br>
</form>
.....

It is importand that the input fields have the correct names. To find out which fields are required and which names they have see the module-documentation. In the case of the guestbook? we need a username (if the user is not logged on) - Guestbook_username, a message (text) - Guestbook_message and we need a submit button with the name Guestbook_createEntry to trigger the function.

<%
Core core = new Core (pageContext);
Guestbook gb = (Guestbook)core.getModule(Guestbook.class);
gb.createEntry(); 
%>

It is important to understand that createEntry() will not be processed as long as a there is no field "Guestbook_createEntry" being submitted (either by a form, or in the URL or by setting the field using java). In other words we can call the function createEntry in the (for example) third line of the .jsp file - but without submitting the proper form the function will no do anything.

When the page loads createEntry is called. Then the function checks for a request parameter named Guestbook_createEntry (in our case the name of the submit button). At the end of the .jsp file we put the form to post a new message. Since the form has no action the data is passed on to the same page - createEntry is called again - but now we have pressed the submit button and therefore the function is processed and the guestbook entry will be created.

Note: It is a common practice to split the display/form from the action functions by jsp. So you have one view.jsp where the guestbook is being displayed and another one, doit.jsp, that executes createEntry etc. The functions/forms call doit.jsp which execute the functions and then foreward to the view.jsp

As we have learned EVERY Corinis-function returns a xml-tree:

<%=core.parseDom(gb.createEntry(), "show.xsl")%>

With the code above the return tree of the createEntry function (success or nosuccess) is parsed. We are able to show success or error messages to the user. Note that if the function isn't processed (submit button not pressed) the function returns null - which is ignored by parseDom/addDom.

double posts Double posts are a quite common problem. If you create a message and submit the form (no action = same page) we have everything entered in the form in the post parameters, which are read by the createEntry function. The entry is created correctly and successfully but the data is still there. So if you make a page-reload afterwards, the same entry is posted again.

The solution is to use a doit.jsp file as stated above or using the following function:

if (gb.createEntry()!=null)
{
  response.sendRedirect("somepage.html");
  return;
}

Everytime the createEntry doesn't return null (= function was processed and returned success/nosuccess) we redirect to another page (without the post-parameters).

Appendix

XML of the module Guestbook

<GUESTBOOK>
  <MODULENAME>global</MODULENAME>
  <ENTRYID>-1</ENTRYID>
  <PERSONAL>false</PERSONAL>
  <ENTRY>
      <CREATE>
       <DATE>31.10.2002 02:54</DATE>
       <LDATE>123311020020254</LDATE>
       <USER>
         <NAME>asdd</NAME>
         <ID>15648432465</ID>
         <IP>127.0.0.1</IP>
        </USER>
      </CREATE>
      <MESSAGE>dddddd</MESSAGE>
    </ENTRY>
  <ENTRY>
      <CREATE>
       <DATE>31.09.2002 02:54</DATE>
       <LDATE>123311020020254</LDATE>
       <USER>
         <NAME>guest</NAME>
         <ID>2</ID>
         <IP>127.0.0.1</IP>
        </USER>
      </CREATE>
      <MESSAGE>Message from guest - > hey its my NAME</MESSAGE>
    </ENTRY>
  <ENTRY>
      <CREATE>
       <DATE>1.03.2002 02:54</DATE>
       <LDATE>123311020020254</LDATE>
       <USER>
         <NAME>admin</NAME>
         <ID>1</ID>
         <IP>127.0.0.1</IP>
        </USER>
      </CREATE>
      <MESSAGE>Nachricht des Admins...irgendwas</MESSAGE>
    </ENTRY>
</GUESTBOOK>

The original XSL of the module Guestbook

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <table>
      <tr>
        <td>
          <b>User</b>
        </td>
        <td>
          <b>Date</b>
        </td>
        <td>
          <b>Message</b>
        </td>
      </tr>
      <xsl:for-each select="GUESTBOOK/ENTRY">
        <tr>
          <td>
            <strong>
              <xsl:value-of select="CREATE/USER/NAME"/>
            </strong>
          </td>
          <td>
            <xsl:value-of select="CREATE/DATE"/>
          </td>
          <td>
            <xsl:value-of select="MESSAGE"/>
          </td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

The adapted XSL of the module Guestbook

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <table>
      <tr>
        <td>
          <b>User</b>
        </td>
        <td>
          <b>Date</b>
        </td>
        <td>
          <b>Message</b>
        </td>
      </tr>
      <xsl:for-each select="GUESTBOOK/ENTRY">
        <xsl:sort select="CREATE/LDATE" order="ascending"/>
        <tr>
          <td>
            <xsl:choose>
              <xsl:when test="CREATE/USER/ID=2">
                <xsl:attribute name="style">
                  <xsl:text>color:red</xsl:text>
                </xsl:attribute>
              </xsl:when>
              <xsl:when test="CREATE/USER/ID=1">
                <xsl:attribute name="style">
                  <xsl:text>color:green</xsl:text>
                </xsl:attribute>
              </xsl:when>
              <xsl:otherwise>
                <xsl:attribute name="style">
                  <xsl:text>color:blue</xsl:text>
                </xsl:attribute>
              </xsl:otherwise>
            </xsl:choose>
            <strong>
              <xsl:if test="CREATE/USER/ID='2'">
                Der Schef
              </xsl:if>
              <xsl:value-of select="CREATE/USER/NAME"/>
            </strong><br/>
            ID: <xsl:value-of select="CREATE/USER/ID"/><br/>
            IP: <xsl:value-of select="substring-before(CREATE/USER/IP, '.')"/>
            <xsl:text>.xxx.xxx.xxx</xsl:text>
          </td>
          <td>
            <i>
              <xsl:value-of select="CREATE/DATE"/>
            </i>
          </td>
          <td>
            <xsl:value-of select="MESSAGE"/>
          </td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

An empty JSP File with initialization

<%@ page language="java" import="corinis.*,corinis.modules.*" %>
<%
Core core = new Core (pageContext);
%>
<HTML>
<HEAD><TITLE>empty document</TITLE></HEAD>
<BODY>

</BODY> 
</HTML> 

An empty JSP File with TagLib and Java initialization

<%@ page language="java" import="corinis.*,corinis.modules.*" %>
<%@ taglib uri="/corinisTags" prefix="corinis" %>
Core core = new Core (pageContext);
%>
<HTML>
<HEAD><TITLE>empty document</TITLE></HEAD>
<BODY>

</BODY> 
</HTML>