13 July, 2007

Portlets and GWT

I've tried to search any useful samples of development Portlets with GWT.
But I found only one such sample: Developing_Portlets_with_GWT.

Now I'm investigating possibility of development JSR168 Portlets together with Google Web Tolkit (I'm using JBoss Portal 2.6 and GWT 1.4).

This subject too interesting for me, and, I think, for many other developers, because:
  • GWT is very useful stuff for development AJAX- based web applications.
  • JBoss Portal is powerful and popular platform for this.

If these technologies work together, it will be great!

But there are problems and questions present on this way. I'm going to say about these problems in next posts.
This post about simple portlet based on GWT:


This portlet only receives time from server every second and repaints this time.
There are some source code presented below (I think it helps for someone).



Project files

./build.properties
./build.xml
./local.properties
./src
./src/WEB-INF
./src/WEB-INF/portlet-instances.xml
./src/WEB-INF/portlet.xml
./src/WEB-INF/web.xml
./src/WEB-INF/xlam-object.xml
./src/xqx
./src/xqx/web
./src/xqx/web/xlam
./src/xqx/web/xlam/client
./src/xqx/web/xlam/client/rpc
./src/xqx/web/xlam/client/rpc/XLamService.java
./src/xqx/web/xlam/client/rpc/XLamServiceAsync.java
./src/xqx/web/xlam/client/Time.java
./src/xqx/web/xlam/client/XLam.java
./src/xqx/web/xlam/public
./src/xqx/web/xlam/public/XLam.html
./src/xqx/web/xlam/server
./src/xqx/web/xlam/server/XLamServiceImpl.java
./src/xqx/web/xlam/XLam.gwt.xml
./src/xqx/web/xlam/XLamPortlet.java


portlet-instances.xml

<?xml version="1.0" standalone="yes"?>
<deployments>
<deployment>
<instance>
<instance-id>XLamPortletInstance</instance-id>
<portlet-ref>XLamPortlet</portlet-ref>
</instance>
</deployment>
</deployments>


portlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">

<portlet>
<portlet-name>XLamPortlet</portlet-name>
<portlet-class>xqx.web.xlam.XLamPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>EDIT</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<portlet-info>
<title>XLam Portlet</title>
</portlet-info>
</portlet>
</portlet-app>


web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<servlet>
<servlet-name>XLamService</servlet-name>
<servlet-class>
xqx.web.xlam.server.XLamServiceImpl
</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>XLamService</servlet-name>
<url-pattern>/XLamService</url-pattern>
</servlet-mapping>

</web-app>


xlam-object.xml

<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<parent-ref>default</parent-ref>
<page>
<page-name>XLam</page-name>
<window>
<window-name>XLamPortletWindow</window-name>
<instance-ref>XLamPortletInstance</instance-ref>
<region>left</region>
<height>0</height>
</window>
</page>
</deployment>
</deployments>


XLamService.java

package xqx.web.xlam.client.rpc;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import xqx.web.xlam.client.Time;

public interface XLamService extends RemoteService {

Time getTime();

public static class App {
private static xqx.web.xlam.client.rpc.XLamServiceAsync ourInstance = null;

public static synchronized xqx.web.xlam.client.rpc.XLamServiceAsync getInstance() {
if (ourInstance == null) {
ourInstance = (xqx.web.xlam.client.rpc.XLamServiceAsync) GWT.create(XLamService.class);
((ServiceDefTarget) ourInstance).setServiceEntryPoint(GWT.getModuleBaseURL() + "XLamService");
}
return ourInstance;
}
}
}


XLamServiceAsync.java

package xqx.web.xlam.client.rpc;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface XLamServiceAsync
{
void getTime(AsyncCallback callback);
}



Time.java

package xqx.web.xlam.client;

import com.google.gwt.user.client.rpc.IsSerializable;

public class Time implements IsSerializable
{
private String time;

public String getTime() { return time; }

public Time(String message) { this.time = message; }

public Time() { }
}


XLam.java

package xqx.web.xlam.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import xqx.web.xlam.client.rpc.XLamService;

public class XLam implements EntryPoint
{
private Timer timer;
private Label label = new Label("Wait...");

private class CallBack implements AsyncCallback
{
public void onFailure(Throwable caught)
{
timer.cancel();
Window.alert(caught.getMessage());
}

public void onSuccess(Object result)
{
label.setText(((Time) result).getTime());
}
}

private CallBack callBack = new CallBack();

public void onModuleLoad()
{
RootPanel.get("uid").add(label);

timer = new Timer()
{
public void run()
{
XLamService.App.getInstance().getTime(callBack);
}
};
timer.scheduleRepeating(1000);
}
}


XLam.html (dummy)

<html>
<head>
<title>XLam</title>
</head>
<body>
<script language='javascript' src='xqx.web.xlam.XLam.nocache.js'></script>
<div id='uid'></div>
</body>
</html>


XLamServiceImpl.java

package xqx.web.xlam.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import xqx.web.xlam.client.Time;
import xqx.web.xlam.client.rpc.XLamService;

import java.text.DateFormat;
import java.util.Date;

public class XLamServiceImpl extends RemoteServiceServlet implements XLamService
{
public Time getTime()
{
String out = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL).format(new Date());
return new Time(out);
}
}


XLamPortlet.java

package xqx.web.xlam;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletSecurityException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class XLamPortlet extends GenericPortlet
{
protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, PortletSecurityException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.println("<script language='javascript' src='" + renderRequest.getContextPath() + "/xqx.web.xlam.XLam.nocache.js'></script>");
writer.println("GWT time:");
writer.println("<div id='uid'></div>");
writer.close();
}

protected void doHelp(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, PortletSecurityException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.write("Help");
writer.close();
}

protected void doEdit(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, PortletSecurityException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.println("Edit");
writer.close();
}
}


XLam.gwt.xml

<module>
<inherits name='com.google.gwt.user.User'/>
<entry-point class='xqx.web.xlam.client.XLam'/>
<servlet path="/XLamService" class="xqx.web.xlam.server.XLamServiceImpl"/>
</module>




Build, deploy and view (http://localhost:8080/portal/auth/portal/default/XLam)

For building purpose you may use this Ant file:

build.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<project name="xlam" default="war">

<property file="local.properties"/>
<property file="build.properties"/>

<property name="build" value="build"/>

<property name="jarfile" value="${project.name}.jar"/>
<property name="warfile" value="${project.name}.war"/>

<path id="classpath">
<fileset dir="${jbossportal.lib}" includes="**/*.jar"/>
<fileset dir="${gwt.home}" includes="**/*.jar"/>
<fileset file="${jarfile}"/>
<pathelement location="src"/>
</path>

<target name="clean">
<delete dir="${build}"/>
</target>

<target name="jar" depends="clean">
<mkdir dir="${build}/bin"/>
<javac srcdir="src" destdir="${build}/bin" classpathref="classpath" debug="true"/>
<jar basedir="${build}/bin" jarfile="${build}/${jarfile}"/>
</target>

<target name="war" depends="jar, gwt">
<copy todir="${build}/war">
<fileset dir="${build}/www/${project.package}.${project.name}">
<exclude name="**/*cache.xml"/>
<exclude name="**/history.html"/>
</fileset>
</copy>

<copy todir="${build}/war/WEB-INF">
<fileset dir="src/WEB-INF"/>
</copy>

<copy todir="${build}/war/WEB-INF/lib">
<fileset file="${build}/${jarfile}"/>
<fileset file="${gwt.home}/gwt-servlet.jar"/>
</copy>

<jar basedir="${build}/war" jarfile="${build}/${warfile}"/>
</target>

<target name="gwt">
<mkdir dir="${build}/www"/>
<java classname="com.google.gwt.dev.GWTCompiler" fork="true" dir="${build}" classpathref="classpath">
<arg line="-out www ${project.package}.${project.name}"/>
</java>
</target>

<target name="shell" depends="jar">
<delete dir="${build}/www"/>
<mkdir dir="${build}/www"/>
<java classname="com.google.gwt.dev.GWTShell" fork="true" dir="${build}" classpathref="classpath">
<arg line="-out www ${project.package}.${project.name}/${project.name}.html"/>
</java>
</target>

<target name="undeploy">
<delete file="${jbossportal.node}/deploy/${warfile}"/>
</target>

<target name="deploy" depends="undeploy, war">
<copy file="${build}/${warfile}" todir="${jbossportal.node}/deploy"/>
</target>
</project>


build.properties

project.name=XLam
project.package=xqx.web.xlam
project.sources=xqx/web/xlam


local.properties (* You should replace paths with your real data)

jdk.home=E:/devenv/tools/jdk-1.5.0_04

jbossportal.home=E:/devenv/tools/jboss-portal-2.6
jbossportal.node=${jbossportal.home}/server/default
jbossportal.lib=${jbossportal.node}/deploy/jboss-portal.sar/lib

gwt.home=E:/devenv/tools/gwt-windows-1.4.10
gwt.docs.index=${gwt.home}/doc/html/gwt.html






You may download these sources from Xantorohara.blogspot.com samples