In my last blogpost we got Java backed webscripts working, now let’s try something completely different: defining page snippet as a component in .JSP. Just let’s continue with our last code, which is possible to download, but it’s not necessary, it’s possible to build it all on green meadow (aka after project in roo is created and surf installed).

First thing to do is to add dependency for jstl into Maven’s pom.xml and then update maven dependencies and refresh our project in Eclipse.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>com.springsource.javax.servlet.jsp.jstl</artifactId>
    <version>1.2.0</version>
</dependency>

Now you can get glue on Spring forums, or trust me and create new component type with JSP Renderer: it’s needed to create new directory – /WEB-INF/classes/surf/site/component-types and inside new component type configuration – test.xml.

<?xml version="1.0" encoding="UTF-8"?>
<component-type>
    <id>test</id>
    <title>Test Component Type</title>
    <description>Test Component Type</description>

    <processor mode="view">
        <id>jsp</id>
        <jsp-path></jsp-path>
    </processor>
</component-type>

Jsp-path is at this time undefined, because we haven’t created any page yet. So let’s do something with that. We need to create new template and new template instance:

roo> surf template create --path test
Created SRC_MAIN_WEBAPP/WEB-INF/templates/test.ftl
roo> surf template instance create --id test --path templates --template test
Created SRC_MAIN_WEBAPP/WEB-INF/templates/test.xml

At this time we have Freemarker template (test.ftl) and template instance (test.xml) inside directory /WEB-INF/templates. We need to edit those files. First let’s add following code into test.ftl. There are four regions defined – three of them inside template scope (already defined by installation of Surf addon) and one with page scope, which we’ll define and bind later.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>${page.title}</title>
  </head>

  <body>
    <div id="page">
      <div id="header">
        <@region id="header" scope="template" />
      </div>
      <div id="horznav">
        <@region id="horznav" scope="template" />
      </div>
      <div id="content">
        <@region id="content" scope="page" />
      </div>
      <div id="footer">
        <@region id="footer" scope="template" />
      </div>
    </div>
  </body>
</html>

Following code (template instance) is definition of components in template scope and is also located in templates directory: test.xml.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<template-instance>
  <title>test</title>
  <description>Instance of test</description>
  <template-type>test</template-type>
  <components>
    <component>
      <region-id>header</region-id>
      <url>/company/header</url>
    </component>
    <component>
      <region-id>horznav</region-id>
      <url>/navigation/horizontal</url>
    </component>
    <component>
      <region-id>footer</region-id>
      <url>/company/footer</url>
    </component>
  </components>
</template-instance>

Now we can create new page based on previously defined template-instance and add link to our new page to horizontal bar. For those actions we can use roo:

roo> surf page create --id test --path pagestest --templateInstance test
Created SRC_MAIN_WEBAPP/WEB-INF/pages/test
Created SRC_MAIN_WEBAPP/WEB-INF/pages/test/test.xml

roo> surf page association create --sourceId home --destId test
Managed SRC_MAIN_WEBAPP/WEB-INF/pages/home/home.xml

As written in roo output, directory test inside pages is created and test.xml within. This file is page configuration and we have to define our content for region defined in template. But not necessary, it’s good idea to check our work now. So let’s try to Run it on server… It’s ugly, but it works! :-)

First try

First try

That’s cool, but our aim is to create working .jsp page. How to do that? What about simply create that page? :-) So let’s create test.jsp inside /WEB-INF/pages/test and fill it with some simple code:

<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt'%>

<%@ page import="java.util.*"  %>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<h1>Test jsp</h1>

<%
  String someText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

  List<String> l = new ArrayList<String>();
  l.add("Maecenas iaculis odio id eros fermentum non tempus erat interdum.");
  l.add("Sed mi orci, dignissim vitae cursus hendrerit, congue sed odio. ");
  l.add("Vivamus quam diam, dapibus sit amet placerat a, tempus at magna.");

  session.setAttribute("someText", someText);
  session.setAttribute("l", l);
%>

<p>${someText }</p>

<c:forEach var="x" items="${l }" >
    <p>${x}</p>
</c:forEach>

That’s our page. Now we need to connect it with previously created component type – /WEB-INF/classes/surf/site/component-types/test.xml. In time of creation we omit jsp-path, so fill it up now:

<jsp-path>/WEB-INF/pages/test/test.jsp</jsp-path>

Last thing to do is to put our shiny new component-type into page. In template we defined region, which is filled in page scope. That’s that components section in page config – /WEB-INF/pages/test/test.xml. It’s good idea to add some title and some styling like border and background thanks to chrome element:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<page>
  <id>test</id>
  <title>test</title>
  <template-instance>test</template-instance>
  <authentication>none</authentication>
  <components>
    <component>
      <region-id>content</region-id>
      <component-type-id>test</component-type-id>
      <chrome>box</chrome>
      <title>JSP inside</title>
    </component>
  </components>
</page>

After rebuild and redeploy we have our jsp component working, as you can see at http://localhost:8080/webscripts/test. Congratulations, good work!

Final application look

Final application look

Ah, in case you got lost, there is package with working sourcecode for this whole example.