This guide provides a tutorial for creating portlets with JSR-223 compliant scripting languages.
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.
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.
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.
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();
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
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()
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();
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); } } );
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>
For simplicity, the following dependencies are provided for each script language.
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>
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>
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>
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>
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>
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.
Add your script portlet into a portal page. You must have the permission to add portlets into the page.
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.