Monday, 1 March 2010

Maven, Jython & Glassfish Example

I keep meaning to get stuck in and learn some Python, and especially make use of some Jython. After coming across this post about using Jython with Glassfish, I thought I'd give it a go myself.

This post is about creating a Maven WAR project making use of Python scripts running on embedded Jython on an embedded Glassfish v3 instance.

Here is the projects POM:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>org.adrianwalker.maven.skeleton.war.jython.glassfish</groupId>
  <artifactId>maven-war-jython-glassfish-example</artifactId>
  <packaging>war</packaging>
  <version>0.1.0</version>
  <name>Maven WAR-Jython-Glassfish Example</name>

  <description>
    Example project for creating a Jython WAR running on Glassfish.
    
    Usage: mvn clean install embedded-glassfish:run
  </description>

  <url>http://www.adrianwalker.org</url>

  <organization>
    <name>adrianwalker.org</name>
    <url>http://www.adrianwalker.org</url>
  </organization>

  <developers>
    <developer>
      <name>Adrian Walker</name>
      <email>ady.walker@gmail.com</email>
      <organization>adrianwalker.org</organization>
      <organizationUrl>http://www.adrianwalker.org</organizationUrl>
    </developer>
  </developers>

  <repositories>
    <!--
    Use project lib directory as repository
    -->
    <repository>
      <id>project</id>
      <url>file://${basedir}/lib</url>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>java.net</id>
      <url>http://download.java.net/maven/glassfish</url>
    </pluginRepository>
  </pluginRepositories>

  <build>
    <finalName>example</finalName>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <webResources>
            <webResource>
              <directory>${basedir}/src/main/python</directory>
              <includes>
                <include>**/*.py</include>
              </includes>
            </webResource>
          </webResources>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.glassfish</groupId>
        <artifactId>maven-embedded-glassfish-plugin</artifactId>
        <configuration>
          <port>8080</port>
          <app>${project.build.directory}/${build.finalName}.war</app>
          <instanceRoot>${project.build.directory}/glassfish</instanceRoot>
          <contextRoot>${build.finalName}</contextRoot>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <!--
    Jython version 2.5.1 and it's standard library
    are included in the project lib directory
    -->
    <dependency>
      <groupId>org.python</groupId>
      <artifactId>jython</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>org.python</groupId>
      <artifactId>jython-lib</artifactId>
      <version>2.5.1</version>
    </dependency>
  </dependencies>
</project>

I couldn't find the latest version (2.5.1) of the Jython JAR in any Maven repository, so I have included it with the project source code in the lib directory. Also, I wanted the Jython instance to be completely self contained, so instead of referencing an install external to the project, I have JAR'ed up the standard library and included it in the project as lib/jython-lib-2.5.1.jar.

The project uses the embedded Glassfish v3 plugin to quickly start a basic configuration Glassfish server.

PyServlet, distributed with Jython is used to create Java Servlets using Jython source files. It is configured in the project's web.xml:

web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="Message" version="2.5">

  <servlet>
    <servlet-name>PyServlet</servlet-name>
    <servlet-class>org.python.util.PyServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>PyServlet</servlet-name>
    <url-pattern>*.py</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>Calendar.py</welcome-file>
  </welcome-file-list>
</web-app>

Python code to create a Java servlet which uses the Python calendar library:

Calendar.py

import time
import calendar
from javax.servlet.http import HttpServlet

class Calendar (HttpServlet):
  def doGet(self, request, response):
    response.setContentType ("text/html")
    out = response.getWriter()

    out.println ("""
    <html>
      <head>
        <title>Calendar</title>
      </head>
      <body>
        <h1>Calendar</h1>
        <pre>%s</pre>
      </body>
    </html>
    """ % calendar.calendar(time.localtime()[0]))

Run the project with 'mvn clean install embedded-glassfish:run' and point your brower at http://localhost:8080/example/.

Source Code