Script Bridget Portlet Guide

This guide provides a tutorial for creating portlets with JSR-223 compliant scripting languages.

1. The ScriptPortlet

The ScriptPortlet (org.apache.portals.bridges.script.ScriptPortlet) is the bridge portlet which evaluates the scripted portlet source to initialize a portlet instance and dispatch each invocation to the scripted portlet instance.

In the portlet descriptor (portlet.xml), the ScriptPortlet is provided as portlet-class. The ScriptPortlet is configured with some init parameters for script sources which implement the real portlet or the real portlet preferences validator.


  1. The ScriptPortlet initializes a ScriptEngine based on either engine name or the type of the script source.
  2. The ScriptPortlet evaluates the script source to load a scripted portlet. If script preferences validator is also configured, it evaluates the validator script source to load a scripted preferences validator.
  3. The ScriptEngine returns an evaluated object to the ScriptPortlet. Now, the ScriptPortlet dispatches all the invocations to the script objects.
    The evaluated object from the portlet script source must be either a javax.portlet.Portlet instance or a javax.portlet.Portlet class.
    Also, the evaluated object from the portlet script preferences validator must be either a javax.portlet.PreferencesValidator instance or a javax.portlet.PreferencesValidator class.

With the ScriptPortlet bridge portlet, you can just provide your script sources. The ScriptPortlet will care everything to create ScriptEngine and to use your script codes.

2. Scripted 'Hello World!' Portlets with Groovy, JRuby, Jython, BeanShell and Rhino JavaScript

If you use a script language which is JSR-223 compliant, then you can implement full-featured portlets with the script language.

Here are "Hello, World!" example portlets implemented by Groovy, JRuby, Jython, BeanShell or Rhino JavaScript. You can choose any.

Groovy example

In this example, HelloGroovy.groovy implements a simple portlet in Groovy.

Note: The last statement creates a portlet instance to be passed to the ScriptPortlet as script evaluation result via the ScriptEngine.

import javax.portlet.GenericPortlet;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

/**
 * HelloGroovy.groovy
 */
public class HelloGroovy extends GenericPortlet
{
    public void doView(RenderRequest request, RenderResponse response)
    {
        String greeting = "<H1>Hello, Groovy!</H1>";
        response.getWriter().println(greeting);
    }
}

// Return portlet instance as a last evaluated object
// because ScriptPortlet expects the evaluated result object 
// as a portlet class or non-initialized portlet instance.
new HelloGroovy();
        

JRuby example

In this example, HelloJRuby.rb implements a simple portlet in JRuby.

Note: The last statement creates a portlet instance to be passed to the ScriptPortlet as script evaluation result via the ScriptEngine.

require 'java'

#
# HelloJRuby.rb
#
class HelloJRuby < javax.portlet.GenericPortlet
    
    def doView(request, response)
        greeting = "<H1>Hello, JRuby!</H1>"
        response.writer.println(greeting)
    end
    
end

# Return portlet instance as a last evaluated object
# because ScriptPortlet expects the evaluated result object 
# as a portlet class or non-initialized portlet instance.
HelloJRuby.new
        

Jython example

In this example, HelloJython.py implements a simple portlet in Jython.

Note: The last statement creates a portlet instance to be passed to the ScriptPortlet as script evaluation result via the ScriptEngine.

from javax.portlet import GenericPortlet

#
# HelloJython.py
#
class HelloJython(GenericPortlet):
    def doView(self, request, response):
        greeting = "<H1>Hello, Jython!</H1>"
        response.writer.println(greeting)
        
    

# Return portlet instance as a last evaluated object
# because ScriptPortlet expects the evaluated result object 
# as a portlet class or non-initialized portlet instance.
value = HelloJython()
        

BeanShell example

In this example, HelloBeanShell.bsh implements a simple portlet in BeanShell.

Note: The last statement creates a portlet instance to be passed to the ScriptPortlet as script evaluation result via the ScriptEngine.

import javax.portlet.GenericPortlet;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

/**
 * HelloBeanShell.bsh
 */
class HelloBeanShell extends GenericPortlet
{
    public void doView(RenderRequest request, RenderResponse response)
    {
        String greeting = "<H1>Hello, BeanShell!</H1>";
        response.getWriter().println(greeting);
    }
}

// Return portlet instance as a last evaluated object
// because ScriptPortlet expects the evaluated result object 
// as a portlet class or non-initialized portlet instance.
new HelloBeanShell();
        

Rhino JavaScript example

In this example, HelloRhino.js implements a simple portlet in Rhino JavaScript.

Note: The last statement creates a portlet instance to be passed to the ScriptPortlet as script evaluation result via the ScriptEngine.

importPackage(Packages.javax.portlet);

/**
 * HelloRhino.js
 */

// Return portlet instance as a last evaluated object
// because ScriptPortlet expects the evaluated result object 
// as a portlet class or non-initialized portlet instance.
new GenericPortlet(
    {
        doView: function(request, response) {
            greeting = "<H1>Hello, Rhino JavaScript!</H1>";
            response.getWriter().println(greeting);
        }
    }
);
        

3. The portlet.xml

Edit your portlet.xml like the following example.

Please refer to the comments on each init parameter for details.

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app id="velocitysimplest" version="1.0">
  
  <portlet>
    <portlet-name>HelloGroovy</portlet-name>
    <display-name>Hello Groovy</display-name>
    <portlet-class>org.apache.portals.bridges.script.ScriptPortlet</portlet-class>
   
    <!-- Optional init parameter for script engine 
    If this init parameter is not set, the ScriptPortlet will look up a script engine automatically
    by the mimeType or the extension of the script source file. -->
    <init-param>
      <name>engine</name>
      <!-- 
        Note: You can set other script engine which support JSR-223 ScriptEngine
        such as 'groovy', 'jruby', 'jython'.
      --> 
      <value>groovy</value>
    </init-param>
   
    <!-- Optional init parameter for the key for portlet/preferencesValidator class or 
    portlet/preferencesValidator instance which is evaluated and returned by the script.
    By default, when this init parameter is not set, ScriptPortlet retrieves 
    the last evaluated object from the script.
    If you set this to 'value', then ScriptPortlet retrieves an object named 'value' 
    from the bindings of the script engine.
    Depending on script engines, this init parameter should be properly configured 
    because some script engines do not return the last evaluated object. -->
    <init-param>
      <name>eval-key</name>
      <value>value</value>
    </init-param>
   
    <!-- Required init parameter for script source path -->
    <init-param>
      <name>source</name>
      <!--
        Note: You can set script source in three ways. 
        The first is to use context relative path,
        the second is to use file: url, 
        and the third is to classpath: uri.
        Here are the examples for each way.
      -->
      <!--
        <value>/WEB-INF/groovy/HelloGroovy.groovy</value>
        <value>file:/C:/Program Files/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovy.groovy</value>
        <value>classpath:org/apache/portals/bridges/script/HelloGroovy.groovy</value>
      -->
      <value>classpath:org/apache/portals/bridges/script/HelloGroovy.groovy</value>
    </init-param>
   
    <!-- Optional init parameter for script file content encoding. The default value is 'UTF-8'. -->
    <init-param>
      <name>encoding</name>
      <value>UTF-8</value>
    </init-param>
   
    <!-- Optional init parameter for auto-refresh option.
    If auto-refresh is true, then a modification of script source can be refreshed automatically.
    By default, this option is set to false. -->
    <init-param>
      <name>auto-refresh</name>
      <value>true</value>
    </init-param>
   
    <!-- Optional init parameter for refresh-delay option.
    When auto-refresh is true, this init parameter sets the milliseconds of automatic refreshing interval.
    By default, this option is set to 60000 milliseconds (a minute). -->
    <init-param>
      <name>refresh-delay</name>
      <value>60000</value>
    </init-param>
    
    <!-- Optional init parameter for script preferences validator path -->
    <init-param>
      <name>validator</name>
      <!--
       Note: You can set script preferences validator source in three ways. 
       The first is to use context relative path,
       the second is to use file: url, 
       and the third is to classpath: uri.
       Here are the examples for each way.
      -->
      <!--
       <value>/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
       <value>file:/C:/Program Files/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
       <value>classpath:org/apache/portals/bridges/script/HelloGroovyPrefsValidator.groovy</value>
      -->
      <value>classpath:org/apache/portals/bridges/script/HelloGroovyPrefsValidator.groovy</value>
    </init-param>
   
    <!-- The followings are not special for ScriptPortlet, but normal configurations for a portlet. -->
    <supports>
      <mime-type>text/html</mime-type>
      <portlet-mode>VIEW</portlet-mode>
      <portlet-mode>EDIT</portlet-mode>
      <portlet-mode>HELP</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <portlet-info>
      <title>Hello Groovy</title>
      <short-title>Hello Groovy</short-title>
      <keywords>demo,groovy</keywords>
    </portlet-info>
    <portlet-preferences>
      <preference>
        <name>message</name>
        <value>Hello, Groovy!</value>
      </preference>
      <preferences-validator>org.apache.portals.bridges.script.ScriptPortletPreferencesValidator</preferences-validator>
    </portlet-preferences>
   
  </portlet>
 
</portlet-app>
          

4. The Dependency JARs

For simplicity, the following dependencies are provided for each script language.

For Groovy Portlet Developers

You can add the following dependency only in your project to use ScriptPortlet with your preferred script langauge.

<dependency>
  <groupId>org.apache.portals.bridges</groupId>
  <artifactId>portals-bridges-script-dependencies-groovy</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>
        

For JRuby Portlet Developers

You can add the following dependency only in your project to use ScriptPortlet with your preferred script langauge.

<dependency>
  <groupId>org.apache.portals.bridges</groupId>
  <artifactId>portals-bridges-script-dependencies-jruby</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>
        

For Jython Portlet Developers

You can add the following dependency only in your project to use ScriptPortlet with your preferred script langauge.

<dependency>
  <groupId>org.apache.portals.bridges</groupId>
  <artifactId>portals-bridges-script-dependencies-jython</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>
        

For BeanShell Portlet Developers

You can add the following dependency only in your project to use ScriptPortlet with your preferred script langauge.

<dependency>
  <groupId>org.apache.portals.bridges</groupId>
  <artifactId>portals-bridges-script-dependencies-beanshell</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>
        

For Rhino JavaScript Portlet Developers

You can add the following dependency only in your project to use ScriptPortlet with your preferred script langauge.

<dependency>
  <groupId>org.apache.portals.bridges</groupId>
  <artifactId>portals-bridges-script-dependencies-rhino</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>
        

5. Deploy the WAR file

After building the war file, copy the war file of your portlet application to $CATALINA_HOME/webapps/jetspeed/WEB-INF/deploy/. Jetspeed-2 will deploy your portlet application automatically.

6. The PSML

Add your script portlet into a portal page. You must have the permission to add portlets into the page.

7. Additional Notes

Note: You may need to increase the permanent generation size of your JVM to run script portlets without OutOfMemoryError errors.
Because JSR-223 Scripting Engine implementations depend on dynamic proxy solutions, it requires more permanent generation space. By default, it is 64MB. Increasing it to be -XX:MaxPermSize=128m might be a good start.
Please see http://wiki.apache.org/tomcat/FAQ/Memory for detail.