Search code examples
maven-2java-web-startsamplemaven-webstart-plugin

Looking for Webstart Maven Plugin sample application


I am looking for source code for a complete application that uses the Webstart Maven Plugin.

Any ideas?


Solution

  • I tried the webstart plugin in a prrof of concept involving an embedded tomcat server. The plugin is bound to the package phase and takes a longtime to execute, I would recommend to invoke it manually from the command line. It generates a zip file in the target directory containing the jnlp file and all dependencies. This file can then be extraced and put on a webserver. The url in the pom should point to this path on the server. When started, the app runs a tomcat server on localhost port 8080 with a simple servlet that just returns the requested path as a string.

    Let me know if this works for you.

    Here is the pom of the project, the plugin configuration was mostly copied from the documentation here

    <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/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>net.jhorstmann</groupId>
        <artifactId>EmbeddedTomcatWebstart</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>EmbeddedTomcatWebstart</name>
        <url>http://localhost/jnlp/</url>
        <organization>
            <name>Organisation</name>
        </organization>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <tomcat.version>7.0.6</tomcat.version>
        </properties>
        <repositories>
            <repository>
                <id>jboss</id>
                <url>http://repository.jboss.org/nexus/content/groups/public/</url>
            </repository>
            <repository>
                <id>sonatype</id>
                <url>http://oss.sonatype.org/content/repositories/releases/</url>
            </repository>
        </repositories>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.5</source>
                        <target>1.5</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>2.3.1</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>net.jhorstmann.embeddedtomcat7.App</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo.webstart</groupId>
                    <artifactId>webstart-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <!-- bind to phase, I prefer to call it manualls -->
                            <phase>package</phase>
                            <goals>
                                <goal>jnlp-inline</goal> <!-- use jnlp, jnlp-inline or jnlp-single as appropriate -->
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!--outputDirectory></outputDirectory--> <!-- not required?? -->
    
                        <!-- Set to true to exclude all transitive dependencies. Default is false. -->
                        <excludeTransitive>false</excludeTransitive>
    
                        <!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
                        <libPath>lib</libPath>
                        <outputJarVersions>true</outputJarVersions>
                        <!-- [optional] transitive dependencies filter - if omitted, all transitive dependencies are included -->
                        <dependencies>
                            <!-- Note that only groupId and artifactId must be specified here. because of a limitation of the Include/ExcludesArtifactFilter -->
                            <!--
                            <includes>
                                <include>commons-logging:commons-logging</include>
                                <include>commons-cli:commons-cli</include>
                            </includes>
                            -->
                            <!--
                            <excludes>
                                <exclude></exclude>
                            <excludes>
                            -->
                        </dependencies>
    
                        <!--
                        <resourcesDirectory>${project.basedir}/src/main/jnlp/resources</resourcesDirectory>
                        -->
                        <!-- default value -->
    
                        <!-- JNLP generation -->
                        <jnlp>
                            <!-- default values -->
                            <!--inputTemplateResourcePath>${project.basedir}</inputTemplateResourcePath-->
                            <!--inputTemplate>src/main/jnlp/template.vm</inputTemplate--> <!-- relative to inputTemplateResourcePath -->
                            <outputFile>app.jnlp</outputFile> <!-- defaults to launch.jnlp -->
    
                            <!-- used to automatically identify the jar containing the main class. -->
                            <!-- this is perhaps going to change -->
                            <mainClass>net.jhorstmann.embeddedtomcat7.App</mainClass>
                        </jnlp>
    
    
                        <!-- SIGNING -->
                        <!-- defining this will automatically sign the jar and its dependencies, if necessary -->
                        <sign>
                            <keystore>${basedir}/keystore</keystore>
                            <keypass>password</keypass>  <!-- we need to override passwords easily from the command line. ${keypass} -->
                            <storepass>password</storepass> <!-- ${storepass} -->
                            <!--storetype>fillme</storetype-->
                            <alias>EmbeddedTomcatWebstart</alias>
    
                            <!--validity>fillme</validity-->
    
                            <!-- only required for generating the keystore -->
                            <dnameCn>EmbeddedTomcatWebstart</dnameCn>
                            <dnameOu>Organisation Unit</dnameOu>
                            <dnameO>Organisation</dnameO>
                            <dnameL>Location</dnameL>
                            <dnameSt>State</dnameSt>
                            <dnameC>Country</dnameC>
    
                            <verify>true</verify> <!-- verify that the signing operation succeeded -->
    
                            <!-- KEYSTORE MANAGEMENT -->
                            <keystoreConfig>
                                <delete>true</delete> <!-- delete the keystore -->
                                <gen>true</gen>       <!-- optional shortcut to generate the store. -->
                            </keystoreConfig>
                        </sign>
    
                        <!-- BUILDING PROCESS -->
    
                        <pack200>true</pack200>
                        <gzip>true</gzip> <!-- default force when pack200 false, true when pack200 selected ?? -->
    
                        <!-- causes a version attribute to be output in each jar resource element, optional, default is false -->
                        <outputJarVersions>false</outputJarVersions>
    
                        <!--install>false</install--> <!-- not yet supported -->
                        <verbose>true</verbose>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <dependencies>
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-catalina</artifactId>
                <version>${tomcat.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-coyote</artifactId>
                <version>${tomcat.version}</version>
            </dependency>
        </dependencies>
    </project>
    

    Here is a custom template for the jnlp file placed at src/main/jnlp/template.vm, I can't remember why I needed that exactly:

    <?xml version="1.0" encoding="utf-8"?>
    <jnlp
        spec="$jnlpspec"
        codebase="$project.Url"
        href="$outputFile">
      <information>
        <title>$project.Name</title>
        <vendor>$project.Organization.Name</vendor>
        <homepage href="$project.Url"/>
        <description>$project.Description</description>
    #if($offlineAllowed)
        <offline-allowed/>
    #end
      </information>
    #if($allPermissions)
      <security>
         <all-permissions/>
      </security>
    #end
      <resources>
        <j2se version="$j2seVersion"/>
         $dependencies
      </resources>
      <application-desc main-class="$mainClass"/>
    </jnlp>
    

    This is the main class at src/main/java/net/jhorstmann/embeddedtomcat7/App.java

    package net.jhorstmann.embeddedtomcat7;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.servlet.ServletException;
    import org.apache.catalina.Context;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.Wrapper;
    import org.apache.catalina.startup.Tomcat;
    
    public class App {
    
        public static void main(String[] args) throws LifecycleException, ServletException, IOException {
            File tmpDir = new File(System.getProperty("java.io.tmpdir"));
            File webappDir = new File(tmpDir, "embeddedtomcat7");
            webappDir.mkdir();
    
            final Tomcat tomcat = new Tomcat();
            tomcat.setPort(8080);
            tomcat.setBaseDir(tmpDir.getAbsolutePath());
            tomcat.getConnector().setURIEncoding("UTF-8");
    
            String contextPath = "/";
    
            Context context = tomcat.addContext(contextPath, webappDir.getAbsolutePath());
            Wrapper wrapper = tomcat.addServlet(contextPath, "Test", new TestServlet());
            //Wrapper wrapper = tomcat.addServlet(contextPath, "Async", new AsyncServlet());
            //wrapper.setAsyncSupported(true);
    
            wrapper.addMapping("/*");
    
            tomcat.start();
    
            tomcat.getServer().await();
        }
    }
    

    And finally a servlet at src/main/java/net/jhorstmann/embeddedtomcat7/TestServlet.java

    package net.jhorstmann.embeddedtomcat7;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class TestServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html; charset=utf-8");
            PrintWriter writer = resp.getWriter();
            writer.println("<h1>" + req.getPathInfo() + "</h1>");
            writer.close();
        }
    }